commit 031582ea2c345ad8889c3edf3040c5d18a2ac392 Author: Beyhan Oğur Date: Sun Apr 26 22:11:03 2026 +0300 first commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..514a032 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +node_modules +.next +.git +.gitignore +.env.development.local +.env.test.local +.env.production.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* +.DS_Store +*.pem +README.md +SETUP.md +.vscode +.idea +coverage +.nyc_output +*.log +drizzle +.env* diff --git a/.env b/.env new file mode 100644 index 0000000..ec458fa --- /dev/null +++ b/.env @@ -0,0 +1,20 @@ +#DATABASE_URL=postgres://cloud:gg7678290@10.80.80.70/image_api +#DATABASE_URL=postgresql://cloud:gg7678290@10.80.80.70:5432/image_api?search_path=public +DATABASE_URL=postgresql://cloud:gg7678290@188.132.232.119:5455/image_apiv2?search_path=public +BETTER_AUTH_SECRET=dB89kiKf56igxrB783yb3UyQToQIPZ93cRKADyq1yQEJ8EU4JRw5GlxBmGvQMu8e +REGISTER_ENABLE=true +BETTER_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_APP_URL=http://localhost:3000 +JWT_SECRET=dB89kiKf56igxrB783yb3UyQToQIPZ93cRKADyq1yQEJ8EU4JRw5GlxBmGvQMu8e + +# https://4f3dc7a1aa54f4ba52803e952d6cf6be.r2.cloudflarestorage.com/image-api + + +# local devop +# https://pub-79ea55a4c5a943c48147a7f1460049f2.r2.dev +# Cloudflare R2 Storage (Europa Server) +R2_ACCOUNT_ID=4f3dc7a1aa54f4ba52803e952d6cf6be +R2_ACCESS_KEY_ID=177784973745076ce943e02b267cf139 +R2_SECRET_ACCESS_KEY=9fcf11d84de480e0bee89f23703c655582c0b0035bcaee828ef0fe187b0d4b63 +R2_BUCKET_NAME=resimlerim +R2_PUBLIC_URL=https://flare.beyhano.com.tr diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f30f9d2 --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# Database +DATABASE_URL=postgresql://user:password@localhost:5432/image_api + +# Better Auth +BETTER_AUTH_SECRET=your-secret-key-here-min-32-characters +BETTER_AUTH_URL=https://image.beyhano.com.tr + +# App Settings +REGISTER_ENABLE=true +NODE_ENV=production + +# App URLs (production) +NEXT_PUBLIC_APP_URL=https://image.beyhano.com.tr +APP_URL=https://flare.beyhano.com.tr + +# JWT Secret +JWT_SECRET=your-jwt-secret-key-min-32-characters-long +# Cloudflare R2 Storage +R2_ACCOUNT_ID=your-cloudflare-account-id +R2_ACCESS_KEY_ID=your-r2-access-key +R2_SECRET_ACCESS_KEY=your-r2-secret-access-key +R2_BUCKET_NAME=your-bucket-name +R2_PUBLIC_URL=https://your-public-domain.com diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..3deee04 --- /dev/null +++ b/.env.local @@ -0,0 +1,23 @@ +#DATABASE_URL=postgres://cloud:gg7678290@10.80.80.70/image_api +#DATABASE_URL=postgresql://cloud:gg7678290@10.80.80.70:5432/image_api?search_path=public +DATABASE_URL=postgresql://cloud:gg7678290@188.132.232.119:5455/image_apiv2?search_path=public +BETTER_AUTH_SECRET=dB89kiKf56igxrB783yb3UyQToQIPZ93cRKADyq1yQEJ8EU4JRw5GlxBmGvQMu8e +REGISTER_ENABLE=true +BETTER_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_APP_URL=http://localhost:3000 +JWT_SECRET=dB89kiKf56igxrB783yb3UyQToQIPZ93cRKADyq1yQEJ8EU4JRw5GlxBmGvQMu8e + +# https://4f3dc7a1aa54f4ba52803e952d6cf6be.r2.cloudflarestorage.com/image-api + + +# local devop +# https://pub-79ea55a4c5a943c48147a7f1460049f2.r2.dev +# Cloudflare R2 Storage (Europa Server) +R2_ACCOUNT_ID=4f3dc7a1aa54f4ba52803e952d6cf6be +R2_ACCESS_KEY_ID=177784973745076ce943e02b267cf139 +R2_SECRET_ACCESS_KEY=9fcf11d84de480e0bee89f23703c655582c0b0035bcaee828ef0fe187b0d4b63 +R2_BUCKET_NAME=resimlerim +R2_PUBLIC_URL=https://flare.beyhano.com.tr + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c260fd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000..4ea72a9 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml new file mode 100644 index 0000000..7ef04e2 --- /dev/null +++ b/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000..1f2ea11 --- /dev/null +++ b/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000..8648f94 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/image-apiv2.iml b/.idea/image-apiv2.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/image-apiv2.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1c7ccb5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ADMIN_PANEL.md b/ADMIN_PANEL.md new file mode 100644 index 0000000..0463706 --- /dev/null +++ b/ADMIN_PANEL.md @@ -0,0 +1,313 @@ +# Admin Panel & Role-Based Access Control (RBAC) + +## Genel Bakış + +Bu proje artık kapsamlı bir rol tabanlı erişim kontrol (RBAC) sistemine sahiptir. Kullanıcılar rollere atanabilir ve bu roller belirli izinler sağlar. + +## Roller + +### 1. **User** (Varsayılan) +- Sadece kendi resimlerini yükleyebilir +- Sadece kendi resimlerini görebilir +- Sadece kendi resimlerini silebilir + +### 2. **Moderator** +- Kendi resimlerini yükleyebilir +- **TÜM** kullanıcıların resimlerini görebilir +- **TÜM** resimleri silebilir +- Moderasyon yetkisi + +### 3. **Admin** +- **TÜM** moderator izinlerine sahiptir +- Kullanıcıları yönetebilir (listeleme, silme) +- Kullanıcı rollerini değiştirebilir +- Tam sistem kontrolü + +## İzinler + +| İzin | User | Moderator | Admin | +|------|------|-----------|-------| +| `IMAGE_UPLOAD` | ✅ | ✅ | ✅ | +| `IMAGE_VIEW_OWN` | ✅ | ✅ | ✅ | +| `IMAGE_VIEW_ANY` | ❌ | ✅ | ✅ | +| `IMAGE_DELETE_OWN` | ✅ | ✅ | ✅ | +| `IMAGE_DELETE_ANY` | ❌ | ✅ | ✅ | +| `USER_VIEW` | ❌ | ❌ | ✅ | +| `USER_DELETE` | ❌ | ❌ | ✅ | +| `USER_MANAGE_ROLES` | ❌ | ❌ | ✅ | +| `USER_MANAGE_PERMISSIONS` | ❌ | ❌ | ✅ | +| `USER_MANAGE_API_KEYS` | ❌ | ❌ | ✅ | + +## Admin Panel + +Admin paneline erişim: **http://localhost:3000/admin** + +### Özellikler + +1. **Kullanıcı Listesi** + - Tüm kullanıcıları görüntüleme + - Kullanıcı detayları (email, rol, doğrulama durumu, kayıt tarihi) + +2. **Rol Yönetimi** + - Dropdown menüden rol seçerek anında güncelleme + - Kendi rolünü değiştirememe koruması + +3. **Kullanıcı Silme** + - Kullanıcıyı ve tüm verilerini silme + - Kullanıcının resimleri ve API anahtarları da silinir + - Kendi hesabını silememe koruması + +4. **İstatistikler** + - Toplam kullanıcı sayısı + - Admin sayısı + - Moderatör sayısı + +## API Endpoint'leri + +### Admin API + +#### 1. Kullanıcıları Listele +```http +GET /api/v1/admin/users +Authorization: Bearer +``` + +**Response:** +```json +{ + "success": true, + "data": { + "users": [ + { + "id": "user-id", + "name": "John Doe", + "email": "john@example.com", + "role": "user", + "emailVerified": true, + "createdAt": "2024-01-01T00:00:00.000Z" + } + ], + "total": 1 + } +} +``` + +#### 2. Kullanıcı Rolünü Değiştir +```http +PATCH /api/v1/admin/users/:id/role +Authorization: Bearer +Content-Type: application/json + +{ + "role": "moderator" +} +``` + +**Response:** +```json +{ + "success": true, + "message": "Kullanıcı rolü başarıyla güncellendi", + "data": { + "userId": "user-id", + "newRole": "moderator" + } +} +``` + +**Koşullar:** +- Sadece admin yetkisi +- Kendi rolünü değiştiremez +- Geçerli roller: `user`, `moderator`, `admin` + +#### 3. Kullanıcı Sil +```http +DELETE /api/v1/admin/users/:id +Authorization: Bearer +``` + +**Response:** +```json +{ + "success": true, + "message": "Kullanıcı başarıyla silindi", + "data": { + "deletedUserId": "user-id", + "deletedUser": "user@example.com" + } +} +``` + +**Koşullar:** +- Sadece admin yetkisi +- Kendi hesabını silemez +- Kullanıcının tüm resimleri ve API anahtarları da silinir + +### Güncellenmiş Resim API'leri + +#### 1. Resimleri Listele +```http +GET /api/v1/images +Authorization: Bearer +``` + +**Davranış:** +- **User**: Sadece kendi resimlerini görür +- **Moderator/Admin**: TÜM resimleri görür + +#### 2. Resim Sil +```http +DELETE /api/v1/images/:id +Authorization: Bearer +``` + +**Davranış:** +- **User**: Sadece kendi resimlerini silebilir +- **Moderator/Admin**: Herhangi bir resmi silebilir + +## İlk Admin Oluşturma + +Veritabanında manuel olarak ilk admin kullanıcısını oluşturun: + +```sql +UPDATE "user" +SET role = 'admin' +WHERE email = 'your-email@example.com'; +``` + +Veya direkt database üzerinden: + +```javascript +// Drizzle Studio veya migration ile +import { db } from "./db"; +import { user } from "./db/schema"; +import { eq } from "drizzle-orm"; + +await db.update(user) + .set({ role: "admin" }) + .where(eq(user.email, "your-email@example.com")); +``` + +## Güvenlik Özellikleri + +1. **Kendi Hesap Koruması** + - Admin kendi rolünü değiştiremez + - Admin kendi hesabını silemez + +2. **Yetkilendirme Kontrolleri** + - Her endpoint permission kontrolü yapar + - 401 (Unauthorized): Giriş yapmamış + - 403 (Forbidden): Yetkisi yok + +3. **Cascade Silme** + - Kullanıcı silindiğinde tüm resimleri ve API anahtarları da silinir + +4. **Role Validasyonu** + - Sadece geçerli roller kabul edilir + - Geçersiz rol atama engellenir + +## Kullanım Örnekleri + +### JavaScript/TypeScript (Web) + +```javascript +// Admin paneline giriş (token localStorage'da saklanıyor) +const token = localStorage.getItem("token"); + +// Kullanıcıları listele +const response = await fetch("/api/v1/admin/users", { + headers: { + Authorization: `Bearer ${token}`, + }, +}); + +const { data } = await response.json(); +console.log(data.users); + +// Rol değiştir +await fetch("/api/v1/admin/users/user-id/role", { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ role: "moderator" }), +}); + +// Kullanıcı sil +await fetch("/api/v1/admin/users/user-id", { + method: "DELETE", + headers: { + Authorization: `Bearer ${token}`, + }, +}); +``` + +### cURL + +```bash +# Kullanıcıları listele +curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ + http://localhost:3000/api/v1/admin/users + +# Rol değiştir +curl -X PATCH \ + -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"role":"moderator"}' \ + http://localhost:3000/api/v1/admin/users/USER_ID/role + +# Kullanıcı sil +curl -X DELETE \ + -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ + http://localhost:3000/api/v1/admin/users/USER_ID +``` + +## Migration + +Role field'ını veritabanına eklemek için: + +```bash +# Schema'dan migration oluştur +yarn db:generate + +# Migration'ı çalıştır +yarn db:push +``` + +Veya manuel olarak SQL: + +```sql +ALTER TABLE "user" +ADD COLUMN IF NOT EXISTS role TEXT DEFAULT 'user'; +``` + +## Dosya Yapısı + +``` +app/ +├── lib/ +│ ├── permissions.ts # RBAC sistem tanımları +│ └── api-auth.ts # Auth middleware (role içerir) +├── api/ +│ └── v1/ +│ └── admin/ +│ └── users/ +│ ├── route.ts # GET (list) +│ └── [id]/ +│ ├── route.ts # DELETE +│ └── role/ +│ └── route.ts # PATCH +└── admin/ + └── page.tsx # Admin panel UI +``` + +## Sonraki Adımlar + +1. ✅ Role sistemi eklendi +2. ✅ Permission kontrolleri eklendi +3. ✅ Admin panel oluşturuldu +4. ✅ Kullanıcı yönetimi API'leri eklendi +5. ⏳ Email bildirimleri (rol değişikliği, hesap silme) +6. ⏳ Audit log sistemi (kim ne yaptı?) +7. ⏳ Gelişmiş filtreleme (role göre, tarihe göre) diff --git a/API_README.md b/API_README.md new file mode 100644 index 0000000..0660f8c --- /dev/null +++ b/API_README.md @@ -0,0 +1,351 @@ +# Image API - Resim Manipülasyon API Dokümantasyonu + +Bu API, dış uygulamaların resim yükleme, manipülasyon ve yönetim işlemlerini yapmasına olanak tanır. + +## Base URL +``` +https://image.beyhano.com.tr +# veya development için +http://localhost:3000 +``` + +## Authentication + +API, JWT token tabanlı kimlik doğrulama kullanır. Her istekte `Authorization` header'ında Bearer token gönderilmelidir. + +``` +Authorization: Bearer +``` + +## Endpoints + +### 1. Kayıt Ol (Register) + +Yeni kullanıcı kaydı oluşturur ve JWT token döner. + +**Endpoint:** `POST /api/v1/auth/register` + +**Request Body:** +```json +{ + "email": "user@example.com", + "password": "minimum8karakter", + "name": "Kullanıcı Adı" +} +``` + +**Response (200):** +```json +{ + "success": true, + "message": "Kayıt başarılı", + "data": { + "user": { + "id": "user_123abc", + "email": "user@example.com", + "name": "Kullanıcı Adı" + }, + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } +} +``` + +**Hata Kodları:** +- `400` - Gerekli alanlar eksik veya geçersiz +- `409` - Email adresi zaten kullanımda +- `500` - Sunucu hatası + +--- + +### 2. Giriş Yap (Login) + +Mevcut kullanıcı ile giriş yapar ve JWT token döner. + +**Endpoint:** `POST /api/v1/auth/login` + +**Request Body:** +```json +{ + "email": "user@example.com", + "password": "minimum8karakter" +} +``` + +**Response (200):** +```json +{ + "success": true, + "message": "Giriş başarılı", + "data": { + "user": { + "id": "user_123abc", + "email": "user@example.com", + "name": "Kullanıcı Adı" + }, + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } +} +``` + +**Hata Kodları:** +- `400` - Email veya şifre eksik +- `401` - Geçersiz email veya şifre +- `500` - Sunucu hatası + +--- + +### 3. Resim Yükle ve Manipüle Et + +Resim yükler, belirtilen boyut/kalite/formatta işler ve kaydeder. + +**Endpoint:** `POST /api/v1/images/upload` + +**Headers:** +``` +Authorization: Bearer +Content-Type: multipart/form-data +``` + +**Request Body (FormData):** +- `file` (required): Resim dosyası (max 10MB) +- `width` (optional): Genişlik (px), default: 800, max: 10000 +- `height` (optional): Yükseklik (px), default: 600, max: 10000 +- `quality` (optional): Kalite (1-100), default: 90 +- `format` (optional): Format (jpeg, png, webp, avif), default: jpeg + +**cURL Örneği:** +```bash +curl -X POST https://image.beyhano.com.tr/api/v1/images/upload \ + -H "Authorization: Bearer YOUR_JWT_TOKEN" \ + -F "file=@/path/to/image.jpg" \ + -F "width=1920" \ + -F "height=1080" \ + -F "quality=85" \ + -F "format=webp" +``` + +**Response (200):** +```json +{ + "success": true, + "message": "Resim başarıyla yüklendi", + "data": { + "image": { + "id": "img_xyz789", + "url": "https://image.beyhano.com.tr/uploads/xyz789.webp", + "width": 1920, + "height": 1080, + "format": "webp", + "fileSize": 245678 + } + } +} +``` + +**Hata Kodları:** +- `400` - Dosya eksik, boyut çok büyük veya geçersiz tip +- `401` - Geçersiz veya eksik token +- `500` - Sunucu hatası + +--- + +### 4. Resimleri Listele + +Kullanıcının tüm resimlerini listeler. + +**Endpoint:** `GET /api/v1/images` + +**Headers:** +``` +Authorization: Bearer +``` + +**Response (200):** +```json +{ + "success": true, + "data": { + "images": [ + { + "id": "img_xyz789", + "originalName": "photo.jpg", + "url": "https://image.beyhano.com.tr/uploads/xyz789.webp", + "width": 1920, + "height": 1080, + "quality": 85, + "format": "webp", + "fileSize": 245678, + "createdAt": "2026-01-06T02:00:00.000Z" + } + ], + "total": 1 + } +} +``` + +**Hata Kodları:** +- `401` - Geçersiz veya eksik token +- `500` - Sunucu hatası + +--- + +### 5. Resim Sil + +Belirtilen ID'ye sahip resmi siler. + +**Endpoint:** `DELETE /api/v1/images/{id}` + +**Headers:** +``` +Authorization: Bearer +``` + +**cURL Örneği:** +```bash +curl -X DELETE https://image.beyhano.com.tr/api/v1/images/img_xyz789 \ + -H "Authorization: Bearer YOUR_JWT_TOKEN" +``` + +**Response (200):** +```json +{ + "success": true, + "message": "Resim başarıyla silindi" +} +``` + +**Hata Kodları:** +- `401` - Geçersiz veya eksik token +- `404` - Resim bulunamadı veya size ait değil +- `500` - Sunucu hatası + +--- + +## Örnek Kullanım (JavaScript/Node.js) + +```javascript +// 1. Kayıt ol +const registerResponse = await fetch('https://image.beyhano.com.tr/api/v1/auth/register', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + email: 'user@example.com', + password: 'securepassword123', + name: 'Kullanıcı' + }) +}); +const { data } = await registerResponse.json(); +const token = data.accessToken; + +// 2. Resim yükle +const formData = new FormData(); +formData.append('file', fileInput.files[0]); +formData.append('width', '1920'); +formData.append('height', '1080'); +formData.append('quality', '85'); +formData.append('format', 'webp'); + +const uploadResponse = await fetch('https://image.beyhano.com.tr/api/v1/images/upload', { + method: 'POST', + headers: { 'Authorization': `Bearer ${token}` }, + body: formData +}); +const uploadData = await uploadResponse.json(); +console.log('Yüklenen resim:', uploadData.data.image.url); + +// 3. Resimleri listele +const imagesResponse = await fetch('https://image.beyhano.com.tr/api/v1/images', { + headers: { 'Authorization': `Bearer ${token}` } +}); +const imagesData = await imagesResponse.json(); +console.log('Toplam resim:', imagesData.data.total); + +// 4. Resim sil +const deleteResponse = await fetch(`https://image.beyhano.com.tr/api/v1/images/${imageId}`, { + method: 'DELETE', + headers: { 'Authorization': `Bearer ${token}` } +}); +const deleteData = await deleteResponse.json(); +console.log(deleteData.message); +``` + +## Örnek Kullanım (Python) + +```python +import requests + +# 1. Kayıt ol +register_response = requests.post( + 'https://image.beyhano.com.tr/api/v1/auth/register', + json={ + 'email': 'user@example.com', + 'password': 'securepassword123', + 'name': 'Kullanıcı' + } +) +token = register_response.json()['data']['accessToken'] + +# 2. Resim yükle +with open('image.jpg', 'rb') as f: + upload_response = requests.post( + 'https://image.beyhano.com.tr/api/v1/images/upload', + headers={'Authorization': f'Bearer {token}'}, + files={'file': f}, + data={ + 'width': '1920', + 'height': '1080', + 'quality': '85', + 'format': 'webp' + } + ) +image_url = upload_response.json()['data']['image']['url'] +print(f'Yüklenen resim: {image_url}') + +# 3. Resimleri listele +images_response = requests.get( + 'https://image.beyhano.com.tr/api/v1/images', + headers={'Authorization': f'Bearer {token}'} +) +images = images_response.json()['data']['images'] +print(f'Toplam resim: {len(images)}') + +# 4. Resim sil +delete_response = requests.delete( + f'https://image.beyhano.com.tr/api/v1/images/{image_id}', + headers={'Authorization': f'Bearer {token}'} +) +print(delete_response.json()['message']) +``` + +## Güvenlik + +- JWT token'lar 7 gün geçerlidir +- Şifreler bcrypt ile hashlenmiş olarak saklanır +- Token'ları güvenli bir şekilde saklayın +- HTTPS kullanın (production'da) +- Rate limiting uygulanabilir + +## Limitler + +- Maximum dosya boyutu: 10MB +- Maximum resim boyutu: 10000x10000 px +- Desteklenen formatlar: JPEG, PNG, WebP, AVIF, GIF +- JWT token geçerlilik süresi: 7 gün + +## Hata Yönetimi + +Tüm hata yanıtları şu formatta döner: + +```json +{ + "error": "Hata mesajı burada" +} +``` + +HTTP status kodları: +- `200` - Başarılı +- `400` - Kötü istek (geçersiz parametreler) +- `401` - Kimlik doğrulama hatası +- `404` - Bulunamadı +- `409` - Çakışma (örn: email zaten kullanımda) +- `500` - Sunucu hatası diff --git a/API_TEST.md b/API_TEST.md new file mode 100644 index 0000000..8da2875 --- /dev/null +++ b/API_TEST.md @@ -0,0 +1,84 @@ +# Image API - Test Senaryoları + +## API Test Komutları (cURL) + +### 1. Kayıt Ol +```bash +curl -X POST http://localhost:3000/api/v1/auth/register \ + -H "Content-Type: application/json" \ + -d '{ + "email": "test@example.com", + "password": "test12345", + "name": "Test User" + }' +``` + +### 2. Login +```bash +curl -X POST http://localhost:3000/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{ + "email": "test@example.com", + "password": "test12345" + }' +``` + +Yanıttan `accessToken` değerini alın ve aşağıdaki komutlarda kullanın: +```bash +export TOKEN="buraya_token_yapistirin" +``` + +### 3. Resim Yükle +```bash +curl -X POST http://localhost:3000/api/v1/images/upload \ + -H "Authorization: Bearer $TOKEN" \ + -F "file=@/path/to/image.jpg" \ + -F "width=800" \ + -F "height=600" \ + -F "quality=90" \ + -F "format=webp" +``` + +### 4. Resimleri Listele +```bash +curl -X GET http://localhost:3000/api/v1/images \ + -H "Authorization: Bearer $TOKEN" +``` + +### 5. Resim Sil +```bash +export IMAGE_ID="buraya_image_id_yapistirin" +curl -X DELETE http://localhost:3000/api/v1/images/$IMAGE_ID \ + -H "Authorization: Bearer $TOKEN" +``` + +## Test Flow + +1. Önce register olun ve token alın +2. Token ile resim yükleyin +3. Yüklenen resimleri listeleyin +4. Bir resmi silin +5. Tekrar listeleyin ve silindiğini doğrulayın + +## Hata Testleri + +### Geçersiz Token +```bash +curl -X GET http://localhost:3000/api/v1/images \ + -H "Authorization: Bearer invalid_token" +``` + +### Token Olmadan +```bash +curl -X GET http://localhost:3000/api/v1/images +``` + +### Geçersiz Login +```bash +curl -X POST http://localhost:3000/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{ + "email": "test@example.com", + "password": "yanlis_sifre" + }' +``` diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..0c2cfd2 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,60 @@ +# Docker Deployment Guide + +Bu proje Node.js v24.12.0 ve Yarn 1.22.22 ile Dockerize edilmiştir. + +## Gereksinimler + +- Docker +- Docker Compose + +## Hızlı Başlangıç + +1. `.env` dosyası oluşturun: + +```bash +DATABASE_URL=postgresql://user:password@host:5432/dbname +BETTER_AUTH_SECRET=your-secret-key-here-min-32-characters-long +BETTER_AUTH_URL=http://localhost:3000 +REGISTER_ENABLE=true +``` + +**Not:** `DATABASE_URL` mevcut PostgreSQL sunucunuzun bağlantı bilgilerini içermelidir. Eğer PostgreSQL Docker dışında çalışıyorsa, host IP adresini veya `host.docker.internal` (Mac/Windows) kullanabilirsiniz. + +2. Docker Compose ile başlatın: + +```bash +docker-compose up -d +``` + +3. Veritabanı migration'larını çalıştırın (ilk kurulumda): + +```bash +docker-compose exec image-api yarn db:push +``` + +4. Uygulama `http://localhost:3000` adresinde çalışacaktır. + +## Manuel Docker Build + +Sadece uygulamayı build etmek için: + +```bash +docker build -t image-api . +docker run -p 3000:3000 --env-file .env image-api +``` + +## Production Notları + +- `.env` dosyasında `BETTER_AUTH_SECRET` mutlaka güçlü bir secret olmalıdır (en az 32 karakter) +- Production'da `BETTER_AUTH_URL` gerçek domain'inizi içermelidir +- PostgreSQL veritabanı dış bir sunucuda çalışmaktadır (docker-compose'da dahil değildir) +- `DATABASE_URL` mevcut PostgreSQL sunucunuzun erişilebilir adresini içermelidir (örn: `postgresql://user:pass@10.80.80.70:5432/dbname`) +- Upload klasörü volume olarak mount edilmiştir, böylece veriler kalıcı olur +- Container, host'un network'ündeki PostgreSQL sunucusuna erişebilir + +## Güvenlik + +- Tüm güvenlik header'ları yapılandırılmıştır +- File upload validasyonları eklenmiştir +- Debug bilgileri production'dan kaldırılmıştır +- Input validasyonları eklenmiştir diff --git a/DOKPLOY_TROUBLESHOOTING.md b/DOKPLOY_TROUBLESHOOTING.md new file mode 100644 index 0000000..a65fd3c --- /dev/null +++ b/DOKPLOY_TROUBLESHOOTING.md @@ -0,0 +1,107 @@ +# Dokploy Troubleshooting Guide + +## PostgreSQL Bağlantı Sorunları + +### Hata: `ECONNREFUSED` veya `Failed query` + +Bu hata, uygulamanın PostgreSQL sunucusuna bağlanamadığını gösterir. + +### Kontrol Listesi + +1. **DATABASE_URL Environment Variable Kontrolü** + + Dokploy'da environment variables bölümünde `DATABASE_URL` değerini kontrol edin: + + ```bash + # Doğru format: + DATABASE_URL=postgresql://user:password@host:port/database?search_path=public + + # Örnek: + DATABASE_URL=postgresql://cloud:gg7678290@10.80.80.70:5432/image_api?search_path=public + ``` + +2. **Network Erişimi** + + - Dokploy container'ından PostgreSQL sunucusuna erişilebilir olmalı + - Eğer PostgreSQL farklı bir network'teyse, network yapılandırmasını kontrol edin + - Firewall kurallarını kontrol edin (port 5432 açık olmalı) + +3. **IP Adresi ve Port** + + - Hata mesajında görünen IP/port ile DATABASE_URL'deki IP/port eşleşmeli + - Eğer farklıysa, Dokploy'da environment variable'ı güncelleyin + +4. **Connection String Formatı** + + ```bash + # ✅ Doğru + postgresql://user:password@10.80.80.70:5432/dbname + + # ❌ Yanlış + postgres://user:password@10.80.80.70:5432/dbname # postgres yerine postgresql kullanın + postgresql://user:password@10.80.80.70/dbname # Port eksik + ``` + +5. **Schema Belirtme** + + Eğer `public` dışında bir schema kullanıyorsanız: + ```bash + DATABASE_URL=postgresql://user:password@host:port/dbname?search_path=your_schema + ``` + +### Dokploy'da Environment Variables Ayarlama + +1. Dokploy dashboard'a giriş yapın +2. Projenizi seçin +3. "Environment Variables" bölümüne gidin +4. `DATABASE_URL` değerini kontrol edin/güncelleyin +5. Değişikliklerden sonra container'ı yeniden başlatın + +### Test Komutları + +Container içinden bağlantıyı test etmek için: + +```bash +# Container'a bağlan +docker exec -it image-api-app sh + +# PostgreSQL bağlantısını test et +psql $DATABASE_URL -c "SELECT version();" +``` + +### Yaygın Hatalar ve Çözümleri + +**Hata:** `ECONNREFUSED 10.0.1.215:5455` +- **Sebep:** DATABASE_URL yanlış IP/port içeriyor +- **Çözüm:** Dokploy'da DATABASE_URL'i doğru IP ve port ile güncelleyin + +**Hata:** `timeout expired` +- **Sebep:** Network erişim sorunu veya firewall +- **Çözüm:** Network yapılandırmasını ve firewall kurallarını kontrol edin + +**Hata:** `password authentication failed` +- **Sebep:** Yanlış kullanıcı adı/şifre +- **Çözüm:** DATABASE_URL'deki credentials'ları kontrol edin + +### Örnek Doğru DATABASE_URL + +```bash +# Local PostgreSQL +DATABASE_URL=postgresql://postgres:password@localhost:5432/image_api?search_path=public + +# Remote PostgreSQL +DATABASE_URL=postgresql://cloud:gg7678290@10.80.80.70:5432/image_api?search_path=public + +# SSL ile +DATABASE_URL=postgresql://user:pass@host:5432/dbname?sslmode=require +``` + +### Debug Modu + +Daha detaylı hata mesajları için: + +```bash +# db.ts dosyasında pool.on('error') event handler'ı logları gösterir +# Container loglarını kontrol edin: +docker logs image-api-app +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fc35f4d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +# Node.js v24.12.0 kullan +FROM node:24.12.0-alpine AS base + +# Yarn için corepack'i etkinleştir +RUN corepack enable + +# Dependencies stage - sadece gerekli bağımlılıkları yükle +FROM base AS deps +WORKDIR /app + +# Package dosyalarını kopyala +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +# Builder stage - uygulamayı build et +FROM base AS builder +WORKDIR /app + +# Node modules'ü kopyala +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Build için gerekli environment variables +ENV NEXT_TELEMETRY_DISABLED=1 +# Build-time için dummy değerler (runtime'da gerçek değerler kullanılacak) +ENV DATABASE_URL="postgresql://cloud:gg7678290@database-postgist-5pcspx:5432/image_api?search_path=public" +ENV BETTER_AUTH_SECRET="dB89kiKf56igxrB783yb3UyQToQIPZ93cRKADyq1yQEJ8EU4JRw5GlxBmGvQMu8e" +ENV BETTER_AUTH_URL="https://image.beyhano.com.tr" +ENV REGISTER_ENABLE=false +# Next.js build +RUN yarn build + +# Runner stage - production için minimal image +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +# Güvenlik için non-root user oluştur +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Standalone build'den dosyaları kopyala +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/public ./public + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "server.js"] diff --git a/MemoryBank.md b/MemoryBank.md new file mode 100644 index 0000000..34ca08f --- /dev/null +++ b/MemoryBank.md @@ -0,0 +1,115 @@ +# Memory Bank + +I am Cline, an expert software engineer with a unique characteristic: my memory resets completely between sessions. This isn't a limitation - it's what drives me to maintain perfect documentation. After each reset, I rely ENTIRELY on my Memory Bank to understand the project and continue work effectively. I MUST read ALL memory bank files at the start of EVERY task - this is not optional. + +## Memory Bank Structure + +The Memory Bank consists of core files and optional context files, all in Markdown format. Files build upon each other in a clear hierarchy: + +flowchart TD + PB[projectbrief.md] --> PC[productContext.md] + PB --> SP[systemPatterns.md] + PB --> TC[techContext.md] + + PC --> AC[activeContext.md] + SP --> AC + TC --> AC + + AC --> P[progress.md] + +### Core Files (Required) +1. `projectbrief.md` + - Foundation document that shapes all other files + - Created at project start if it doesn't exist + - Defines core requirements and goals + - Source of truth for project scope + +2. `productContext.md` + - Why this project exists + - Problems it solves + - How it should work + - User experience goals + +3. `activeContext.md` + - Current work focus + - Recent changes + - Next steps + - Active decisions and considerations + - Important patterns and preferences + - Learnings and project insights + +4. `systemPatterns.md` + - System architecture + - Key technical decisions + - Design patterns in use + - Component relationships + - Critical implementation paths + +5. `techContext.md` + - Technologies used + - Development setup + - Technical constraints + - Dependencies + - Tool usage patterns + +6. `progress.md` + - What works + - What's left to build + - Current status + - Known issues + - Evolution of project decisions + +### Additional Context +Create additional files/folders within memory-bank/ when they help organize: +- Complex feature documentation +- Integration specifications +- API documentation +- Testing strategies +- Deployment procedures + +## Core Workflows + +### Plan Mode +flowchart TD + Start[Start] --> ReadFiles[Read Memory Bank] + ReadFiles --> CheckFiles{Files Complete?} + + CheckFiles -->|No| Plan[Create Plan] + Plan --> Document[Document in Chat] + + CheckFiles -->|Yes| Verify[Verify Context] + Verify --> Strategy[Develop Strategy] + Strategy --> Present[Present Approach] + +### Act Mode +flowchart TD + Start[Start] --> Context[Check Memory Bank] + Context --> Update[Update Documentation] + Update --> Execute[Execute Task] + Execute --> Document[Document Changes] + +## Documentation Updates + +Memory Bank updates occur when: +1. Discovering new project patterns +2. After implementing significant changes +3. When user requests with **update memory bank** (MUST review ALL files) +4. When context needs clarification + +flowchart TD + Start[Update Process] + + subgraph Process + P1[Review ALL Files] + P2[Document Current State] + P3[Clarify Next Steps] + P4[Document Insights & Patterns] + + P1 --> P2 --> P3 --> P4 + end + + Start --> Process + +Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state. + +REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy. \ No newline at end of file diff --git a/R2 ClousFlare.txt b/R2 ClousFlare.txt new file mode 100644 index 0000000..c0d9f68 --- /dev/null +++ b/R2 ClousFlare.txt @@ -0,0 +1,10 @@ +Toke Value +0jbuP8PiWCbXglAfFAkfFC_l5bVk8w69WCJT6MtG +Access Key +177784973745076ce943e02b267cf139 +Server Access Key +9fcf11d84de480e0bee89f23703c655582c0b0035bcaee828ef0fe187b0d4b63 +Default +https://4f3dc7a1aa54f4ba52803e952d6cf6be.r2.cloudflarestorage.com +Europa +https://4f3dc7a1aa54f4ba52803e952d6cf6be.eu.r2.cloudflarestorage.com \ No newline at end of file diff --git a/R2_MIGRATION.md b/R2_MIGRATION.md new file mode 100644 index 0000000..8180b13 --- /dev/null +++ b/R2_MIGRATION.md @@ -0,0 +1,142 @@ +# Cloudflare R2 Storage Entegrasyonu + +Bu proje, resim depolamasını yerel dosya sisteminden Cloudflare R2'ye taşımak için güncellenmiştir. + +## Yapılan Değişiklikler + +### 1. Yeni Kütüphane +- **@aws-sdk/client-s3** eklendi (Cloudflare R2, S3-uyumlu API kullanır) + +### 2. Yeni Dosyalar +- **app/lib/r2-storage.ts**: R2 storage işlemleri için yardımcı fonksiyonlar + - `uploadToR2()`: Resim yükleme + - `deleteFromR2()`: Resim silme + - `getContentType()`: Dosya türü belirleme + +### 3. Güncellenen Dosyalar + +#### API Routes (Upload) +- `app/api/images/upload/route.ts` +- `app/api/v1/images/upload/route.ts` + +**Değişiklikler:** +- Yerel dosya sistemi yerine R2'ye yükleme +- `writeFile` ve `mkdir` kaldırıldı +- `uploadToR2()` kullanılıyor +- URL'ler artık tam R2 URL'leri olarak kaydediliyor + +#### API Routes (List) +- `app/api/images/route.ts` +- `app/api/v1/images/route.ts` + +**Değişiklikler:** +- Base URL ekleme kaldırıldı (R2 URL'leri zaten tam URL) +- Direkt olarak veritabanından gelen URL döndürülüyor + +#### API Routes (Delete) +- `app/api/images/[id]/route.ts` +- `app/api/v1/images/[id]/route.ts` + +**Değişiklikler:** +- Yerel dosya silme yerine R2'den silme +- `unlink` yerine `deleteFromR2()` kullanılıyor + +### 4. Environment Variables + +`.env`, `.env.local` ve `.env.example` dosyalarına eklenen değişkenler: + +```env +# Cloudflare R2 Storage (Europa Server) +R2_ACCOUNT_ID=4f3dc7a1aa54f4ba52803e952d6cf6be +R2_ACCESS_KEY_ID=177784973745076ce943e02b267cf139 +R2_SECRET_ACCESS_KEY=9fcf11d84de480e0bee89f23703c655582c0b0035bcaee828ef0fe187b0d4b63 +R2_BUCKET_NAME=resimlerim +R2_PUBLIC_URL=https://images.beyhano.com.tr +``` + +**Not:** Europa server endpoint'i kullanılıyor: `https://{ACCOUNT_ID}.eu.r2.cloudflarestorage.com` + +## R2 Bucket Yapılandırması + +### Gerekli Ayarlar + +1. **Bucket Oluşturma:** + - Cloudflare Dashboard > R2 > Create Bucket + - Bucket adı: `images` (veya .env'de belirtilen) + - Location: Europa + +2. **Public Access:** + - Bucket Settings > Public Access + - Custom Domain ekleyin: `images.beyhano.com.tr` + - CORS ayarlarını yapılandırın (gerekirse) + +3. **API Token:** + - R2 > Manage R2 API Tokens + - Create API Token + - Permissions: Object Read & Write + - Token bilgilerini .env'e ekleyin + +## Avantajlar + +1. **Ölçeklenebilirlik:** Sınırsız depolama kapasitesi +2. **Performans:** CDN entegrasyonu ile hızlı erişim +3. **Maliyet:** Egress ücreti yok (Cloudflare CDN üzerinden) +4. **Güvenilirlik:** Otomatik yedekleme ve dayanıklılık +5. **Bakım:** Sunucu disk alanı yönetimi gerekmez + +## Geriye Dönük Uyumluluk + +Mevcut sistemde `public/uploads/` klasöründe bulunan resimler için: + +1. **Manuel Migrasyon:** Mevcut resimleri R2'ye yükleyin +2. **Veritabanı Güncelleme:** `images` tablosundaki `url` ve `filePath` alanlarını güncelleyin +3. **Eski Dosyalar:** Migrasyon sonrası eski dosyaları silebilirsiniz + +## Test Etme + +### 1. Resim Yükleme Testi +```bash +curl -X POST https://image.beyhano.com.tr/api/images/upload \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -F "file=@test-image.jpg" \ + -F "width=800" \ + -F "height=600" \ + -F "quality=90" \ + -F "format=jpeg" +``` + +### 2. Resim Listeleme Testi +```bash +curl -X GET https://image.beyhano.com.tr/api/images \ + -H "Authorization: Bearer YOUR_TOKEN" +``` + +### 3. Resim Silme Testi +```bash +curl -X DELETE https://image.beyhano.com.tr/api/images/IMAGE_ID \ + -H "Authorization: Bearer YOUR_TOKEN" +``` + +## Sorun Giderme + +### R2 Bağlantı Hatası +- Environment variables'ların doğru olduğundan emin olun +- R2 API Token'ın aktif olduğunu kontrol edin +- Bucket adının doğru olduğunu kontrol edin + +### Upload Hatası +- Dosya boyutunun 10MB'ın altında olduğundan emin olun +- Content-Type'ın doğru ayarlandığını kontrol edin +- R2 bucket'ın write permission'a sahip olduğunu kontrol edin + +### URL Erişim Hatası +- Custom domain'in doğru yapılandırıldığından emin olun +- Public access ayarlarını kontrol edin +- DNS kayıtlarının doğru olduğunu kontrol edin + +## Önemli Notlar + +1. **Güvenlik:** API credentials'ları asla commit etmeyin +2. **Backup:** Kritik resimlerin yedeğini alın +3. **Monitoring:** R2 kullanım metriklerini takip edin +4. **Rate Limiting:** R2 API rate limitlerini göz önünde bulundurun diff --git a/R2_SETUP_CHECKLIST.md b/R2_SETUP_CHECKLIST.md new file mode 100644 index 0000000..27d8fda --- /dev/null +++ b/R2_SETUP_CHECKLIST.md @@ -0,0 +1,190 @@ +# Cloudflare R2 Kurulum Kontrol Listesi + +## ✅ Tamamlanan Adımlar + +### 1. Kod Değişiklikleri +- [x] AWS SDK (@aws-sdk/client-s3) kuruldu +- [x] R2 storage servisi oluşturuldu (app/lib/r2-storage.ts) +- [x] Upload endpoint'leri güncellendi (hem /api hem /api/v1) +- [x] List endpoint'leri güncellendi (R2 URL'leri kullanıyor) +- [x] Delete endpoint'leri güncellendi (R2'den silme) +- [x] Environment variables eklendi (.env, .env.local, .env.example) +- [x] Yerel dosya sistemi referansları kaldırıldı +- [x] Linter hataları temizlendi + +### 2. Yapılandırma +- [x] Europa server endpoint yapılandırıldı +- [x] R2 credentials .env dosyalarına eklendi +- [x] Bucket name: `resimlerim` +- [x] Public URL: `https://images.beyhano.com.tr` + +## 📋 Yapılması Gerekenler (Cloudflare Dashboard) + +### 1. R2 Bucket Kontrolü +- [ ] Cloudflare Dashboard'a giriş yapın +- [ ] R2 > Buckets bölümüne gidin +- [ ] `resimlerim` adında bucket olduğunu kontrol edin +- [ ] Bucket location'ın Europa (EEUR) olduğunu doğrulayın + +### 2. Public Access Ayarları +- [ ] Bucket > Settings > Public Access +- [ ] Custom Domain ekleyin: `images.beyhano.com.tr` +- [ ] DNS kayıtlarını yapılandırın (CNAME veya A record) +- [ ] SSL/TLS sertifikasının aktif olduğunu kontrol edin + +### 3. CORS Ayarları (Gerekirse) +Eğer frontend'den direkt R2'ye erişim gerekiyorsa: +```json +[ + { + "AllowedOrigins": ["https://image.beyhano.com.tr"], + "AllowedMethods": ["GET", "HEAD"], + "AllowedHeaders": ["*"], + "MaxAgeSeconds": 3600 + } +] +``` + +### 4. API Token Kontrolü +- [ ] R2 > Manage R2 API Tokens +- [ ] Token'ın aktif olduğunu kontrol edin +- [ ] Permissions: Object Read & Write +- [ ] Token bilgilerinin .env'de doğru olduğunu doğrulayın + +## 🧪 Test Adımları + +### 1. Yerel Test (Development) +```bash +# Sunucuyu başlat +yarn dev + +# Test resmi yükle +curl -X POST http://localhost:3000/api/images/upload \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -F "file=@test-image.jpg" \ + -F "width=800" \ + -F "height=600" +``` + +### 2. Production Test +```bash +# Test resmi yükle +curl -X POST https://image.beyhano.com.tr/api/images/upload \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -F "file=@test-image.jpg" + +# Resimleri listele +curl -X GET https://image.beyhano.com.tr/api/images \ + -H "Authorization: Bearer YOUR_TOKEN" + +# Resmi tarayıcıda aç (dönen URL'yi kullan) +# Örnek: https://images.beyhano.com.tr/abc123.jpg +``` + +### 3. Kontrol Edilecekler +- [ ] Resim başarıyla yükleniyor +- [ ] R2 bucket'ta resim görünüyor +- [ ] Public URL üzerinden resme erişilebiliyor +- [ ] Resim listesi doğru URL'leri döndürüyor +- [ ] Resim silme işlemi çalışıyor +- [ ] Resim manipülasyonu (resize, format) çalışıyor + +## 🔄 Mevcut Resimlerin Migrasyonu (Opsiyonel) + +Eğer `public/uploads/` klasöründe mevcut resimler varsa: + +### 1. Resimleri R2'ye Yükle +```bash +# AWS CLI veya rclone kullanarak toplu yükleme +# Örnek: rclone sync public/uploads/ r2:resimlerim/ +``` + +### 2. Veritabanını Güncelle +```sql +-- Eski URL'leri yeni R2 URL'leriyle değiştir +UPDATE images +SET url = CONCAT('https://images.beyhano.com.tr/', fileName), + filePath = fileName +WHERE url LIKE '/uploads/%'; +``` + +### 3. Eski Dosyaları Temizle +```bash +# Migrasyon başarılı olduktan sonra +rm -rf public/uploads/* +``` + +## 🚨 Sorun Giderme + +### R2 Bağlantı Hatası +``` +Error: R2'ye yükleme başarısız +``` +**Çözüm:** +- Environment variables'ları kontrol edin +- R2 API Token'ın aktif olduğunu doğrulayın +- Account ID'nin doğru olduğunu kontrol edin + +### Public URL Erişim Hatası +``` +403 Forbidden veya 404 Not Found +``` +**Çözüm:** +- Custom domain yapılandırmasını kontrol edin +- Public access ayarlarını kontrol edin +- DNS propagation'ı bekleyin (24 saat) + +### Upload Başarılı Ama Resim Görünmüyor +**Çözüm:** +- Browser cache'i temizleyin +- R2 bucket'ta dosyanın var olduğunu kontrol edin +- Content-Type header'ının doğru olduğunu kontrol edin + +## 📊 Monitoring + +### Cloudflare Dashboard +- R2 > Analytics +- Storage kullanımı +- Request sayısı +- Bandwidth kullanımı + +### Önemli Metrikler +- Upload success rate +- Average response time +- Error rate +- Storage growth + +## 🔒 Güvenlik Notları + +1. **API Credentials:** + - Asla commit etmeyin + - Production'da environment variables kullanın + - Düzenli olarak rotate edin + +2. **Public Access:** + - Sadece gerekli dosyalar public olsun + - Rate limiting uygulayın + - Hotlink protection düşünün + +3. **Backup:** + - Kritik resimlerin yedeğini alın + - Versioning'i etkinleştirin (R2 settings) + - Disaster recovery planı oluşturun + +## 📝 Notlar + +- R2 egress ücreti yoktur (Cloudflare CDN üzerinden) +- Storage maliyeti: ~$0.015/GB/ay +- Class A operations: $4.50/million (PUT, LIST) +- Class B operations: $0.36/million (GET, HEAD) +- Europa server kullanıldığı için GDPR uyumlu + +## ✅ Son Kontrol + +Deployment öncesi: +- [ ] Tüm environment variables production'da ayarlandı +- [ ] R2 bucket ve custom domain yapılandırıldı +- [ ] Test upload/download/delete çalışıyor +- [ ] Monitoring ve alerting kuruldu +- [ ] Backup stratejisi belirlendi +- [ ] Documentation güncellendi diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fccd2d --- /dev/null +++ b/README.md @@ -0,0 +1,220 @@ +# Image Manipulation API + +Modern, güvenli ve ölçeklenebilir resim yönetim ve manipülasyon platformu. Next.js 16, Better Auth ve Drizzle ORM ile geliştirilmiştir. + +## ✨ Özellikler + +### 🔐 Güvenlik & Kimlik Doğrulama +- **Better Auth** ile session tabanlı kimlik doğrulama +- **JWT** destekli REST API (dış uygulamalar için) +- **Role-Based Access Control (RBAC)** - 3 farklı rol (User, Moderator, Admin) +- API Key yönetimi +- Şifre hashleme (bcrypt) + +### 🎨 Resim İşleme +- **Sharp** kütüphanesi ile hızlı resim manipülasyonu +- Boyutlandırma (width/height) +- Format dönüştürme (JPEG, PNG, WebP, AVIF) +- Kalite ayarı (1-100) +- Otomatik dosya boyutu optimizasyonu + +### 👥 Kullanıcı Yönetimi +- **Admin Panel** - Kullanıcıları yönetme, rol atama, silme +- Kullanıcı profili +- Email doğrulama desteği +- Kayıt açma/kapama kontrolü + +### 📊 Rol ve İzinler + +| Rol | İzinler | +|-----|---------| +| **User** | Kendi resimlerini yükleyebilir, görüntüleyebilir ve silebilir | +| **Moderator** | Tüm resimleri görüntüleyebilir ve silebilir | +| **Admin** | Tüm moderator izinleri + Kullanıcı yönetimi | + +### 🚀 API Özellikleri +- RESTful API tasarımı +- JWT token authentication +- API Key authentication +- Rate limiting (opsiyonel) +- Swagger-style dokümantasyon + +## 📦 Teknolojiler + +- **Framework**: Next.js 16.1.1 (App Router, Turbopack) +- **Auth**: better-auth v1.4.10 +- **Database**: PostgreSQL + Drizzle ORM v0.45.1 +- **Image Processing**: Sharp v0.34.5 +- **Styling**: Tailwind CSS v4 +- **Container**: Docker & Docker Compose +- **Runtime**: Node.js v24.12.0 + +## 🛠️ Kurulum + +### 1. Proje Klonlama +\`\`\`bash +git clone +cd image-api +\`\`\` + +### 2. Ortam Değişkenleri +\`.env\` dosyası oluşturun: +\`\`\`env +DATABASE_URL=postgresql://user:password@localhost:5432/image_api +BETTER_AUTH_SECRET=your-super-secret-key-min-32-chars +BETTER_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_APP_URL=http://localhost:3000 +JWT_SECRET=another-super-secret-key-min-32-characters +REGISTER_ENABLE=true +\`\`\` + +### 3. Docker ile Çalıştırma +\`\`\`bash +# PostgreSQL başlat +docker compose up -d postgres + +# Bağımlılıkları yükle +yarn install + +# Database migration +yarn db:push + +# Development server +yarn dev +\`\`\` + +### 4. İlk Admin Kullanıcısı +\`\`\`bash +# Kayıt ol +# Sonra admin yap: +npx tsx make-admin.ts your-email@example.com +\`\`\` + +## 📚 API Kullanımı + +### Kayıt ve Login +\`\`\`bash +# Kayıt +curl -X POST http://localhost:3000/api/v1/auth/register \\ + -H "Content-Type: application/json" \\ + -d '{"email":"user@example.com","password":"password123","name":"John Doe"}' + +# Login +curl -X POST http://localhost:3000/api/v1/auth/login \\ + -H "Content-Type: application/json" \\ + -d '{"email":"user@example.com","password":"password123"}' + +# Response: {"success":true,"token":"jwt-token-here"} +\`\`\` + +### Resim Yükleme +\`\`\`bash +curl -X POST http://localhost:3000/api/v1/images/upload \\ + -H "Authorization: Bearer YOUR_JWT_TOKEN" \\ + -F "file=@photo.jpg" \\ + -F "width=800" \\ + -F "quality=90" \\ + -F "format=webp" +\`\`\` + +### Resim Listeleme +\`\`\`bash +# User: Sadece kendi resimleri +# Moderator/Admin: Tüm resimler +curl http://localhost:3000/api/v1/images \\ + -H "Authorization: Bearer YOUR_JWT_TOKEN" +\`\`\` + +### Admin - Kullanıcıları Listeleme +\`\`\`bash +curl http://localhost:3000/api/v1/admin/users \\ + -H "Authorization: Bearer ADMIN_JWT_TOKEN" +\`\`\` + +### Admin - Rol Değiştirme +\`\`\`bash +curl -X PATCH http://localhost:3000/api/v1/admin/users/USER_ID/role \\ + -H "Authorization: Bearer ADMIN_JWT_TOKEN" \\ + -H "Content-Type: application/json" \\ + -d '{"role":"moderator"}' +\`\`\` + +Detaylı API dokümantasyonu: **http://localhost:3000/api-docs** + +## 🎯 Sayfalar + +- \`/\` - Anasayfa +- \`/login\` - Giriş yap +- \`/register\` - Kayıt ol (REGISTER_ENABLE=true ise) +- \`/upload\` - Resim yükle +- \`/profile\` - Profil ve resimlerim +- \`/admin\` - Admin panel (sadece adminler) +- \`/api-docs\` - API dokümantasyonu + +## 🔒 Güvenlik Özellikleri + +1. **Password Hashing**: bcrypt ile şifreler güvenle saklanır +2. **JWT Tokens**: 7 günlük geçerlilik süresi +3. **Role-Based Access**: Endpoint bazında yetkilendirme +4. **Session Management**: Better Auth ile güvenli session yönetimi +5. **CORS**: Yapılandırılabilir CORS desteği +6. **Environment Variables**: Hassas bilgiler .env'de + +## 📊 Database Schema + +### Tables +- \`user\` - Kullanıcı bilgileri (email, password_hash, role) +- \`session\` - Aktif oturumlar +- \`account\` - OAuth provider hesapları +- \`verification\` - Email doğrulama +- \`images\` - Yüklenen resimler +- \`apiKeys\` - API anahtarları + +## 🐳 Docker Production Build + +\`\`\`bash +# Build image +docker build -t image-api . + +# Run with docker-compose +docker compose up -d + +# Check logs +docker compose logs -f image-api +\`\`\` + +## 📝 Scripts + +\`\`\`bash +yarn dev # Development server +yarn build # Production build +yarn start # Production server +yarn lint # ESLint +yarn db:generate # Generate migrations +yarn db:push # Push schema to DB +yarn db:studio # Drizzle Studio +\`\`\` + +## 🤝 Katkıda Bulunma + +1. Fork edin +2. Feature branch oluşturun (\`git checkout -b feature/amazing\`) +3. Commit edin (\`git commit -m 'Add amazing feature'\`) +4. Push edin (\`git push origin feature/amazing\`) +5. Pull Request açın + +## 📄 Lisans + +MIT + +## 👨‍💻 Geliştirici + +Beyhan Oğur - [beyhan@beyhan.dev](mailto:beyhan@beyhan.dev) + +--- + +**Daha fazla bilgi için:** +- [API Documentation](./API_README.md) +- [Admin Panel Guide](./ADMIN_PANEL.md) +- [Docker Setup](./DOCKER.md) +- [Security Guide](./SECURITY.md) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..56dcd1d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,61 @@ +# Güvenlik İyileştirmeleri + +Bu dokümanda production'a hazırlık için yapılan güvenlik iyileştirmeleri listelenmektedir. + +## Yapılan İyileştirmeler + +### 1. Debug Bilgilerinin Kaldırılması +- ✅ Production console.log ifadeleri kaldırıldı +- ✅ API response'lardan debug bilgileri çıkarıldı +- ✅ Hata mesajlarında hassas bilgi sızıntısı önlendi + +### 2. File Upload Güvenliği +- ✅ Dosya boyutu limiti eklendi (maksimum 10MB) +- ✅ MIME type validasyonu eklendi +- ✅ Sadece resim dosyaları kabul ediliyor (jpeg, jpg, png, gif, webp, avif) +- ✅ Path traversal koruması (nanoid kullanımı) + +### 3. Input Validasyonu +- ✅ Width/Height validasyonu (1-10000px arası) +- ✅ Quality validasyonu (1-100 arası) +- ✅ Format validasyonu (sadece izin verilen formatlar) +- ✅ Image ID validasyonu (uzunluk ve tip kontrolü) + +### 4. Security Headers +- ✅ Strict-Transport-Security (HSTS) +- ✅ X-Frame-Options +- ✅ X-Content-Type-Options +- ✅ X-XSS-Protection +- ✅ Referrer-Policy +- ✅ Permissions-Policy + +### 5. Authentication & Authorization +- ✅ Tüm API endpoint'lerinde authentication kontrolü +- ✅ User-based authorization (kullanıcılar sadece kendi resimlerini görebilir/silebilir) +- ✅ Better Auth kullanımı (güvenli session yönetimi) + +### 6. Database Security +- ✅ Drizzle ORM kullanımı (SQL injection koruması) +- ✅ Parameterized queries +- ✅ Foreign key constraints + +### 7. Environment Variables +- ✅ Hassas bilgiler environment variable'larda +- ✅ .env.example dosyası oluşturuldu +- ✅ .gitignore'da .env dosyaları ignore ediliyor + +## Production Checklist + +- [ ] `BETTER_AUTH_SECRET` güçlü bir secret olarak ayarlanmalı (min 32 karakter) +- [ ] `BETTER_AUTH_URL` production domain'i ile güncellenmeli +- [ ] `DATABASE_URL` production veritabanı bağlantısı ile güncellenmeli +- [ ] HTTPS kullanılmalı (production'da) +- [ ] Rate limiting eklenmeli (opsiyonel, yüksek trafik için) +- [ ] Monitoring ve logging kurulumu yapılmalı +- [ ] Regular backup stratejisi oluşturulmalı + +## Notlar + +- File upload limiti 10MB olarak ayarlanmıştır. Gerekirse artırılabilir. +- Tüm hata mesajları generic olarak döndürülmektedir (hassas bilgi sızıntısını önlemek için). +- Console.log ifadeleri production'dan kaldırılmıştır, ancak geliştirme ortamında gerekirse eklenebilir. diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..5ef5872 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,76 @@ +# Kurulum Talimatları + +Bu proje Next.js, Better Auth ve Drizzle ORM ile PostgreSQL entegrasyonu içerir. + +## Gereksinimler + +- Node.js 18+ +- PostgreSQL veritabanı +- npm veya yarn + +## Kurulum Adımları + +### 1. Bağımlılıkları Yükleyin + +```bash +npm install +# veya +yarn install +``` + +### 2. Ortam Değişkenlerini Ayarlayın + +Proje kök dizininde `.env` dosyası oluşturun: + +```env +DATABASE_URL=postgresql://user:password@localhost:5432/dbname +BETTER_AUTH_SECRET=your-secret-key-here-minimum-32-characters +BETTER_AUTH_URL=http://localhost:3000 +REGISTER_ENABLE=true +``` + +**Önemli:** +- `BETTER_AUTH_SECRET` en az 32 karakter uzunluğunda güvenli bir rastgele string olmalıdır. +- `REGISTER_ENABLE` kayıt sayfasını açıp kapatmak için kullanılır. `true` veya `false` değeri alabilir. Varsayılan olarak `true`'dur. + +### 3. Veritabanı Şemasını Oluşturun + +```bash +npm run db:push +# veya +yarn db:push +``` + +Bu komut, `db/schema.ts` dosyasındaki şemaya göre veritabanı tablolarını oluşturacaktır. + +### 4. Geliştirme Sunucusunu Başlatın + +```bash +npm run dev +# veya +yarn dev +``` + +Tarayıcınızda [http://localhost:3000](http://localhost:3000) adresine gidin. + +## Kullanım + +1. **Kayıt Ol:** `/register` sayfasından yeni bir hesap oluşturun +2. **Giriş Yap:** `/login` sayfasından giriş yapın +3. **Profil:** Giriş yaptıktan sonra `/profile` sayfasında kullanıcı bilgilerinizi görüntüleyin + +## Veritabanı Komutları + +- `npm run db:generate` - Migration dosyalarını oluşturur +- `npm run db:push` - Şemayı veritabanına uygular +- `npm run db:studio` - Drizzle Studio'yu açar (veritabanı görüntüleme aracı) + +## Dosya Yapısı + +- `db.ts` - Drizzle veritabanı bağlantısı +- `db/schema.ts` - Veritabanı şema tanımları +- `app/lib/auth.ts` - Better Auth yapılandırması +- `app/api/auth/[...all]/route.ts` - Better Auth API route handler +- `app/login/page.tsx` - Giriş sayfası +- `app/register/page.tsx` - Kayıt sayfası +- `app/profile/page.tsx` - Kullanıcı profil sayfası diff --git a/app/admin/page.tsx b/app/admin/page.tsx new file mode 100644 index 0000000..93d9b55 --- /dev/null +++ b/app/admin/page.tsx @@ -0,0 +1,619 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import Swal from "sweetalert2"; + +interface User { + id: string; + name: string | null; + email: string; + role: string; + emailVerified: boolean; + createdAt: string; +} + +interface AdminApiKeyRow { + id: string; + name: string; + keyPreview: string; + expiresAt: string | null; + daysRemaining: number | null; + remainingLabel: string; + lastUsedAt: string | null; + isActive: boolean; + createdAt: string; +} + +interface Session { + user: { + id: string; + email: string; + name?: string; + role?: string; + }; +} + +export default function AdminPanel() { + const router = useRouter(); + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(true); + const [currentUserRole, setCurrentUserRole] = useState(""); + const [keysModalUser, setKeysModalUser] = useState(null); + const [userKeys, setUserKeys] = useState([]); + const [keysLoading, setKeysLoading] = useState(false); + const [keysPatching, setKeysPatching] = useState(null); + const [expiryDraft, setExpiryDraft] = useState>({}); + + useEffect(() => { + checkAuth(); + }, []); + + const checkAuth = async () => { + try { + const res = await fetch("/api/auth/get-session", { + credentials: "include", + }); + + if (!res.ok) { + router.push("/login"); + return; + } + + const session: Session = await res.json(); + + if (!session.user || session.user.role !== "admin") { + await Swal.fire({ + icon: "error", + title: "Erişim Engellendi", + text: "Bu sayfaya erişim yetkiniz yok. Sadece adminler görebilir.", + confirmButtonColor: "#3b82f6", + }); + router.push("/"); + return; + } + + setCurrentUserRole(session.user.role || "user"); + await fetchUsers(); + } catch (err) { + router.push("/login"); + } + }; + + const fetchUsers = async () => { + setLoading(true); + + try { + const res = await fetch("/api/admin/users", { + credentials: "include", + }); + + if (!res.ok) { + if (res.status === 401) { + router.push("/login"); + return; + } + if (res.status === 403) { + await Swal.fire({ + icon: "error", + title: "Yetki Hatası", + text: "Bu sayfaya erişim yetkiniz yok.", + confirmButtonColor: "#3b82f6", + }); + return; + } + throw new Error("Kullanıcılar yüklenemedi"); + } + + const data = await res.json(); + setUsers(data.data.users); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + } finally { + setLoading(false); + } + }; + + const changeRole = async (userId: string, newRole: string, currentRole: string) => { + const result = await Swal.fire({ + title: "Rol Değiştir", + text: `Bu kullanıcının rolünü "${currentRole}" → "${newRole}" olarak değiştirmek istediğinizden emin misiniz?`, + icon: "question", + showCancelButton: true, + confirmButtonColor: "#3b82f6", + cancelButtonColor: "#6b7280", + confirmButtonText: "Evet, değiştir", + cancelButtonText: "İptal", + }); + + if (!result.isConfirmed) { + await fetchUsers(); + return; + } + + try { + const res = await fetch(`/api/admin/users/${userId}/role`, { + method: "PATCH", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ role: newRole }), + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.error || "Rol güncellenemedi"); + } + + await Swal.fire({ + icon: "success", + title: "Başarılı!", + text: "Kullanıcı rolü güncellendi", + timer: 2000, + showConfirmButton: false, + }); + + await fetchUsers(); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + await fetchUsers(); + } + }; + + const toggleEmailVerification = async (userId: string, currentStatus: boolean, email: string) => { + const newStatus = !currentStatus; + const result = await Swal.fire({ + title: "Email Doğrulama", + text: `${email} için email doğrulamasını ${newStatus ? "aktif" : "pasif"} yapmak istiyor musunuz?`, + icon: "question", + showCancelButton: true, + confirmButtonColor: "#3b82f6", + cancelButtonColor: "#6b7280", + confirmButtonText: "Evet, değiştir", + cancelButtonText: "İptal", + }); + + if (!result.isConfirmed) { + return; + } + + try { + const res = await fetch(`/api/admin/users/${userId}/verification`, { + method: "PATCH", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ emailVerified: newStatus }), + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.error || "Doğrulama güncellenemedi"); + } + + await Swal.fire({ + icon: "success", + title: "Başarılı!", + text: `Email doğrulama ${newStatus ? "aktif edildi" : "pasif edildi"}`, + timer: 2000, + showConfirmButton: false, + }); + + await fetchUsers(); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + } + }; + + const fetchUserKeysList = async (userId: string) => { + setKeysLoading(true); + try { + const res = await fetch(`/api/v1/admin/users/${userId}/api-keys`, { + credentials: "include", + }); + const data = await res.json(); + if (!res.ok) { + throw new Error(data.error || "Anahtarlar yüklenemedi"); + } + setUserKeys(data.data?.keys || []); + } finally { + setKeysLoading(false); + } + }; + + const openApiKeysModal = async (u: User) => { + setKeysModalUser(u); + setUserKeys([]); + setExpiryDraft({}); + try { + await fetchUserKeysList(u.id); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + setKeysModalUser(null); + } + }; + + const patchKeyExpiry = async (userId: string, keyId: string, draft: string) => { + let expiresInDays: number | null; + const t = draft.trim(); + if (t === "") { + expiresInDays = null; + } else { + const n = parseInt(t, 10); + if (!Number.isFinite(n) || n < 0) { + await Swal.fire({ + icon: "warning", + title: "Geçersiz", + text: "Gün sayısı boş (süresiz) veya 0 veya pozitif tam sayı olmalı.", + confirmButtonColor: "#3b82f6", + }); + return; + } + expiresInDays = n === 0 ? null : n; + } + setKeysPatching(keyId); + try { + const res = await fetch( + `/api/v1/admin/users/${userId}/api-keys/${keyId}`, + { + method: "PATCH", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ expiresInDays }), + } + ); + const data = await res.json(); + if (!res.ok) { + throw new Error(data.error || "Güncellenemedi"); + } + await Swal.fire({ + icon: "success", + title: "Güncellendi", + text: "API anahtarı süresi kaydedildi.", + timer: 1800, + showConfirmButton: false, + }); + setExpiryDraft((prev) => { + const next = { ...prev }; + delete next[keyId]; + return next; + }); + await fetchUserKeysList(userId); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + } finally { + setKeysPatching(null); + } + }; + + const deleteUser = async (userId: string, email: string) => { + const result = await Swal.fire({ + title: "Kullanıcıyı Sil", + html: `${email} kullanıcısını silmek istediğinizden emin misiniz?

+ ⚠️ Bu işlem geri alınamaz!
+ Kullanıcının tüm resimleri ve verileri silinecek.`, + icon: "warning", + showCancelButton: true, + confirmButtonColor: "#ef4444", + cancelButtonColor: "#6b7280", + confirmButtonText: "Evet, sil!", + cancelButtonText: "İptal", + }); + + if (!result.isConfirmed) { + return; + } + + try { + const res = await fetch(`/api/admin/users/${userId}`, { + method: "DELETE", + credentials: "include", + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.error || "Kullanıcı silinemedi"); + } + + await Swal.fire({ + icon: "success", + title: "Silindi!", + text: "Kullanıcı başarıyla silindi", + timer: 2000, + showConfirmButton: false, + }); + + await fetchUsers(); + } catch (err: any) { + await Swal.fire({ + icon: "error", + title: "Hata", + text: err.message, + confirmButtonColor: "#3b82f6", + }); + } + }; + + const getRoleBadgeColor = (role: string) => { + switch (role) { + case "admin": + return "bg-red-100 text-red-800 border-red-200"; + case "moderator": + return "bg-blue-100 text-blue-800 border-blue-200"; + default: + return "bg-gray-100 text-gray-800 border-gray-200"; + } + }; + + if (loading) { + return ( +
+
+
+

Yükleniyor...

+
+
+ ); + } + + return ( +
+
+
+

Admin Panel

+

Kullanıcı yönetimi ve rol atama

+
+ +
+
+ + + + + + + + + + + + + {users.map((user) => ( + + + + + + + + + ))} + +
KullanıcıEmailRolDoğrulamaKayıt Tarihiİşlemler
+
+ {user.name || "İsimsiz"} +
+
{user.id.substring(0, 8)}
+
{user.email} + + + + + {new Date(user.createdAt).toLocaleDateString("tr-TR")} + +
+ + +
+
+
+
+ + {keysModalUser && ( +
+
+
+
+

API anahtarları

+

+ {keysModalUser.email} — süre: bugünden itibaren gün sayısı (boş veya 0 = + süresiz) +

+
+ +
+ {keysLoading ? ( +

Yükleniyor…

+ ) : userKeys.length === 0 ? ( +

Bu kullanıcının henüz API anahtarı yok.

+ ) : ( +
+ + + + + + + + + + + + {userKeys.map((k) => ( + + + + + + + + + ))} + +
İsimÖnizlemeMevcut bitişKalan süreYeni süre (gün) +
{k.name}{k.keyPreview} + {k.expiresAt + ? new Date(k.expiresAt).toLocaleString("tr-TR") + : "—"} + + + {k.remainingLabel} + + + + setExpiryDraft((prev) => ({ + ...prev, + [k.id]: e.target.value, + })) + } + className="w-28 rounded border border-gray-300 px-2 py-1 text-sm" + /> + + +
+
+ )} +
+
+ )} + +
+
+

Toplam Kullanıcı

+

{users.length}

+
+
+

Admin Sayısı

+

+ {users.filter((u) => u.role === "admin").length} +

+
+
+

Moderatör Sayısı

+

+ {users.filter((u) => u.role === "moderator").length} +

+
+
+

Doğrulananlar

+

+ {users.filter((u) => u.emailVerified).length} +

+
+
+
+
+ ); +} diff --git a/app/api-docs/page.tsx b/app/api-docs/page.tsx new file mode 100644 index 0000000..06c0bf9 --- /dev/null +++ b/app/api-docs/page.tsx @@ -0,0 +1,318 @@ +"use client"; + +import Link from "next/link"; + +export default function ApiDocsPage() { + return ( +
+
+ {/* Header */} +
+ + + + + Ana Sayfa + +
+ + {/* Title */} +
+

+ API Dokümantasyonu +

+

+ Image Manipulation API - REST API Kullanım Kılavuzu +

+
+ + {/* Content */} +
+ {/* Base URL */} +
+

+ Base URL +

+
+ + https://v2.beyhano.com.tr + +
+
+ + {/* Authentication */} +
+

+ Authentication +

+

+ İki yöntem desteklenir: JWT (login/register ile alınan token) veya + hesabınız için oluşturduğunuz API anahtarı ( + img_ ile başlar). İkisi de aynı header ile + gönderilir: +

+
+ + Authorization: Bearer <jwt_token_veya_img_..._api_key> + +
+

+ API anahtarını web arayüzünde profil sayfasından oluşturabilirsiniz; isteğe bağlı + gün sınırı koyabilir veya süresiz bırakabilirsiniz. Admin, kullanıcı anahtarlarının + süresini panelden güncelleyebilir. +

+
+ + {/* Endpoints */} +
+

+ Endpoints +

+ + {/* Register */} +
+
+ + POST + + + /api/v1/auth/register + +
+

+ Yeni kullanıcı kaydı oluşturur ve JWT token döner. +

+
+
+{`{
+  "email": "user@example.com",
+  "password": "minimum8karakter",
+  "name": "Kullanıcı Adı"
+}`}
+                
+
+
+ + {/* Login */} +
+
+ + POST + + + /api/v1/auth/login + +
+

+ Mevcut kullanıcı ile giriş yapar ve JWT token döner. +

+
+
+{`{
+  "email": "user@example.com",
+  "password": "minimum8karakter"
+}`}
+                
+
+
+ + {/* API Keys */} +
+
+ + GET + + + /api/v1/api-keys + +
+

+ Oturum veya Bearer ile: kendi API anahtarlarınızı listeler (tam değer dönmez). +

+
+ + POST + + + /api/v1/api-keys + +
+

+ Body:{" "} + + {`{ "name": "Etiket", "expiresInDays": 30 }`} + {" "} + — expiresInDays yok/null/0 ise süresiz. + Yanıtta tam anahtar yalnızca bir kez gelir. +

+
+ + {/* Upload Image */} +
+
+ + POST + + + /api/v1/images/upload + +
+

+ Resim yükler, belirtilen boyut/kalite/formatta işler ve kaydeder. (multipart/form-data) +

+
+
file (required): Resim dosyası (max 10MB)
+
width (optional): Genişlik (px), default: 800
+
height (optional): Yükseklik (px), default: 600
+
quality (optional): Kalite (1-100), default: 90
+
format (optional): jpeg, png, webp, avif
+
+
+ + {/* List Images */} +
+
+ + GET + + + /api/v1/images + +
+

+ Kullanıcının tüm resimlerini listeler. +

+
+ + {/* Delete Image */} +
+
+ + DELETE + + + /api/v1/images/:id + +
+

+ Belirtilen ID'ye sahip resmi siler. +

+
+
+ + {/* Example Code */} +
+

+ Örnek Kullanım (JavaScript) +

+
+
+{`// 1. Kayıt ol
+const registerResponse = await fetch(
+  'https://image.beyhano.com.tr/api/v1/auth/register',
+  {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({
+      email: 'user@example.com',
+      password: 'securepassword123',
+      name: 'Kullanıcı'
+    })
+  }
+);
+const { data } = await registerResponse.json();
+const token = data.accessToken;
+
+// 2. Resim yükle
+const formData = new FormData();
+formData.append('file', fileInput.files[0]);
+formData.append('width', '1920');
+formData.append('quality', '85');
+formData.append('format', 'webp');
+
+const uploadResponse = await fetch(
+  'https://image.beyhano.com.tr/api/v1/images/upload',
+  {
+    method: 'POST',
+    headers: { 'Authorization': \`Bearer \${token}\` },
+    body: formData
+  }
+);
+const uploadData = await uploadResponse.json();
+console.log('URL:', uploadData.data.image.url);`}
+              
+
+
+ + {/* Features */} +
+

+ Özellikler ve Limitler +

+
+
+

+ ✅ Desteklenen Formatlar +

+
    +
  • • JPEG / JPG
  • +
  • • PNG
  • +
  • • WebP
  • +
  • • AVIF
  • +
  • • GIF
  • +
+
+
+

+ ⚙️ Limitler +

+
    +
  • • Max dosya: 10MB
  • +
  • • Max boyut: 10000x10000 px
  • +
  • • Token süresi: 7 gün
  • +
  • • HTTPS zorunlu (production)
  • +
+
+
+
+ + {/* Download Full Docs */} +
+

Detaylı Dokümantasyon

+

+ Tüm endpoint'ler, hata kodları ve örnekler için tam dokümantasyonu indirin. +

+ + + + + GitHub'da Görüntüle + +
+
+
+
+ ); +} diff --git a/app/api/admin/users/[id]/role/route.ts b/app/api/admin/users/[id]/role/route.ts new file mode 100644 index 0000000..4a00d29 --- /dev/null +++ b/app/api/admin/users/[id]/role/route.ts @@ -0,0 +1,70 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { isAdmin, UserRole, updateUserRole } from "@/app/lib/permissions"; + +/** + * PATCH /api/admin/users/[id]/role + * Kullanıcının rolünü değiştir (Sadece admin - Web Session) + */ +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const session = await auth.api.getSession({ + headers: request.headers, + }); + + if (!session?.user) { + return NextResponse.json({ error: "Giriş yapmalısınız" }, { status: 401 }); + } + + // Admin kontrolü + const userRole = (session.user as any).role || "user"; + if (!isAdmin(userRole)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler rol değiştirebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + const body = await request.json(); + const { role } = body; + + // Role validasyonu + const validRoles: UserRole[] = ["user", "admin", "moderator"]; + if (!role || !validRoles.includes(role)) { + return NextResponse.json( + { error: "Geçersiz rol. Geçerli roller: user, admin, moderator" }, + { status: 400 } + ); + } + + // Kendi rolünü değiştirmeyi engelle + if (userId === session.user.id) { + return NextResponse.json( + { error: "Kendi rolünüzü değiştiremezsiniz" }, + { status: 400 } + ); + } + + // Rolü güncelle + await updateUserRole(userId, role); + + return NextResponse.json({ + success: true, + message: "Kullanıcı rolü başarıyla güncellendi", + data: { + userId, + newRole: role, + }, + }); + } catch (error: any) { + console.error("Rol güncelleme hatası:", error); + return NextResponse.json( + { error: "Rol güncellenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/admin/users/[id]/route.ts b/app/api/admin/users/[id]/route.ts new file mode 100644 index 0000000..71cd3be --- /dev/null +++ b/app/api/admin/users/[id]/route.ts @@ -0,0 +1,75 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { hasPermission, PERMISSIONS } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user, images, apiKeys } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +/** + * DELETE /api/admin/users/[id] + * Kullanıcıyı sil (Sadece admin - Web Session) + * Kullanıcının tüm resimleri ve API anahtarları da silinir + */ +export async function DELETE( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const session = await auth.api.getSession({ + headers: request.headers, + }); + + if (!session?.user) { + return NextResponse.json({ error: "Giriş yapmalısınız" }, { status: 401 }); + } + + // Permission kontrolü + const userRole = (session.user as any).role || "user"; + if (!hasPermission(userRole, PERMISSIONS.USER_DELETE)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler kullanıcı silebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + + // Kendi hesabını silmeyi engelle + if (userId === session.user.id) { + return NextResponse.json( + { error: "Kendi hesabınızı silemezsiniz" }, + { status: 400 } + ); + } + + // Kullanıcının var olup olmadığını kontrol et + const targetUser = await db.select().from(user).where(eq(user.id, userId)).limit(1); + if (targetUser.length === 0) { + return NextResponse.json({ error: "Kullanıcı bulunamadı" }, { status: 404 }); + } + + // Kullanıcının resimlerini sil + await db.delete(images).where(eq(images.userId, userId)); + + // Kullanıcının API anahtarlarını sil + await db.delete(apiKeys).where(eq(apiKeys.userId, userId)); + + // Kullanıcıyı sil + await db.delete(user).where(eq(user.id, userId)); + + return NextResponse.json({ + success: true, + message: "Kullanıcı başarıyla silindi", + data: { + deletedUserId: userId, + deletedUser: targetUser[0].email, + }, + }); + } catch (error: any) { + console.error("Kullanıcı silme hatası:", error); + return NextResponse.json( + { error: "Kullanıcı silinemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/admin/users/[id]/verification/route.ts b/app/api/admin/users/[id]/verification/route.ts new file mode 100644 index 0000000..ac0f822 --- /dev/null +++ b/app/api/admin/users/[id]/verification/route.ts @@ -0,0 +1,72 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +/** + * PATCH /api/admin/users/[id]/verification + * Kullanıcının email doğrulamasını değiştir (Sadece admin - Web Session) + */ +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const session = await auth.api.getSession({ + headers: request.headers, + }); + + if (!session?.user) { + return NextResponse.json({ error: "Giriş yapmalısınız" }, { status: 401 }); + } + + // Admin kontrolü + const userRole = (session.user as any).role || "user"; + if (!isAdmin(userRole)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler doğrulama değiştirebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + const body = await request.json(); + const { emailVerified } = body; + + // Boolean validasyonu + if (typeof emailVerified !== "boolean") { + return NextResponse.json( + { error: "emailVerified boolean olmalıdır" }, + { status: 400 } + ); + } + + // Email doğrulama durumunu güncelle + const result = await db + .update(user) + .set({ emailVerified }) + .where(eq(user.id, userId)) + .returning(); + + if (result.length === 0) { + return NextResponse.json({ error: "Kullanıcı bulunamadı" }, { status: 404 }); + } + + return NextResponse.json({ + success: true, + message: `Email doğrulama ${emailVerified ? "aktif edildi" : "pasif edildi"}`, + data: { + userId, + emailVerified, + }, + }); + } catch (error: any) { + console.error("Email doğrulama güncelleme hatası:", error); + return NextResponse.json( + { error: "Email doğrulama güncellenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/admin/users/route.ts b/app/api/admin/users/route.ts new file mode 100644 index 0000000..61ce9f2 --- /dev/null +++ b/app/api/admin/users/route.ts @@ -0,0 +1,57 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user } from "@/db/schema"; +import { desc } from "drizzle-orm"; + +/** + * GET /api/admin/users + * Tüm kullanıcıları listele (Sadece admin - Web Session) + */ +export async function GET(request: NextRequest) { + const session = await auth.api.getSession({ + headers: request.headers, + }); + + if (!session?.user) { + return NextResponse.json({ error: "Giriş yapmalısınız" }, { status: 401 }); + } + + // Admin kontrolü + const userRole = (session.user as any).role || "user"; + if (!isAdmin(userRole)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler kullanıcıları görüntüleyebilir." }, + { status: 403 } + ); + } + + try { + const users = await db + .select({ + id: user.id, + name: user.name, + email: user.email, + role: user.role, + emailVerified: user.emailVerified, + createdAt: user.createdAt, + }) + .from(user) + .orderBy(desc(user.createdAt)); + + return NextResponse.json({ + success: true, + data: { + users, + total: users.length, + }, + }); + } catch (error: any) { + console.error("Kullanıcı listesi hatası:", error); + return NextResponse.json( + { error: "Kullanıcılar yüklenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/auth/[...all]/route.ts b/app/api/auth/[...all]/route.ts new file mode 100644 index 0000000..438bff0 --- /dev/null +++ b/app/api/auth/[...all]/route.ts @@ -0,0 +1,4 @@ +import { auth } from "@/app/lib/auth"; +import { toNextJsHandler } from "better-auth/next-js"; + +export const { GET, POST } = toNextJsHandler(auth); diff --git a/app/api/config/route.ts b/app/api/config/route.ts new file mode 100644 index 0000000..0e00c85 --- /dev/null +++ b/app/api/config/route.ts @@ -0,0 +1,7 @@ +import { NextResponse } from "next/server"; + +export async function GET() { + return NextResponse.json({ + registerEnabled: process.env.REGISTER_ENABLE === "true", + }); +} diff --git a/app/api/images/[id]/route.ts b/app/api/images/[id]/route.ts new file mode 100644 index 0000000..43ca633 --- /dev/null +++ b/app/api/images/[id]/route.ts @@ -0,0 +1,80 @@ +import { NextRequest, NextResponse } from "next/server"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { eq, and } from "drizzle-orm"; +import { auth } from "@/app/lib/auth"; +import { deleteFromR2 } from "@/app/lib/r2-storage"; + +async function getUserId(request: NextRequest): Promise { + try { + const session = await auth.api.getSession({ + headers: request.headers, + }); + return session?.user?.id || null; + } catch { + return null; + } +} + +export async function DELETE( + request: NextRequest, + { params }: { params: Promise<{ id: string }> | { id: string } } +) { + try { + const userId = await getUserId(request); + if (!userId) { + return NextResponse.json( + { message: "Yetkisiz erişim" }, + { status: 401 } + ); + } + + // Next.js 15'te params async olabilir + const resolvedParams = await Promise.resolve(params); + const imageId = resolvedParams.id; + + // Input validation + if (!imageId || typeof imageId !== "string" || imageId.length > 255) { + return NextResponse.json( + { message: "Geçersiz resim ID" }, + { status: 400 } + ); + } + + // Resmi veritabanından bul + const image = await db + .select() + .from(images) + .where(and(eq(images.id, imageId), eq(images.userId, userId))) + .limit(1); + + if (image.length === 0) { + return NextResponse.json( + { message: "Resim bulunamadı veya yetkiniz yok" }, + { status: 404 } + ); + } + + const imageData = image[0]; + + // R2'den dosyayı sil + try { + await deleteFromR2(imageData.fileName); + } catch (error) { + console.error("R2'den silme hatası:", error); + // Hata olsa bile devam et, veritabanından sil + } + + // Veritabanından sil + await db.delete(images).where(eq(images.id, imageId)); + + return NextResponse.json({ + message: "Resim başarıyla silindi", + }); + } catch (error: any) { + return NextResponse.json( + { message: "Silme işlemi başarısız" }, + { status: 500 } + ); + } +} diff --git a/app/api/images/route.ts b/app/api/images/route.ts new file mode 100644 index 0000000..724d642 --- /dev/null +++ b/app/api/images/route.ts @@ -0,0 +1,53 @@ +import { NextRequest, NextResponse } from "next/server"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { eq, desc } from "drizzle-orm"; +import { auth } from "@/app/lib/auth"; + +async function getUserId(request: NextRequest): Promise { + try { + const session = await auth.api.getSession({ + headers: request.headers, + }); + return session?.user?.id || null; + } catch { + return null; + } +} + +export async function GET(request: NextRequest) { + try { + const userId = await getUserId(request); + if (!userId) { + return NextResponse.json( + { message: "Yetkisiz erişim" }, + { status: 401 } + ); + } + + const userImages = await db + .select() + .from(images) + .where(eq(images.userId, userId)) + .orderBy(desc(images.createdAt)); + + return NextResponse.json({ + images: userImages.map((img) => ({ + id: img.id, + originalName: img.originalName, + url: img.url, // R2 URL'leri zaten tam URL olarak kaydedildi + width: img.width, + height: img.height, + quality: img.quality, + format: img.format, + fileSize: img.fileSize, + createdAt: img.createdAt.toISOString(), + })), + }); + } catch (error: any) { + return NextResponse.json( + { message: "Resimler yüklenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/images/upload/route.ts b/app/api/images/upload/route.ts new file mode 100644 index 0000000..9ca5107 --- /dev/null +++ b/app/api/images/upload/route.ts @@ -0,0 +1,154 @@ +import { NextRequest, NextResponse } from "next/server"; +import sharp from "sharp"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { nanoid } from "nanoid"; +import { auth } from "@/app/lib/auth"; +import { uploadToR2, getContentType } from "@/app/lib/r2-storage"; + +async function getUserId(request: NextRequest): Promise { + try { + const session = await auth.api.getSession({ + headers: request.headers, + }); + return session?.user?.id || null; + } catch { + return null; + } +} + +export async function POST(request: NextRequest) { + try { + const userId = await getUserId(request); + if (!userId) { + return NextResponse.json( + { message: "Yetkisiz erişim" }, + { status: 401 } + ); + } + + const formData = await request.formData(); + const file = formData.get("file") as File; + + if (!file) { + return NextResponse.json( + { message: "Dosya bulunamadı" }, + { status: 400 } + ); + } + + // File size validation (max 10MB) + const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB + if (file.size > MAX_FILE_SIZE) { + return NextResponse.json( + { message: "Dosya boyutu çok büyük. Maksimum 10MB olmalıdır." }, + { status: 400 } + ); + } + + // File type validation + const allowedMimeTypes = ["image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp", "image/avif"]; + if (!allowedMimeTypes.includes(file.type)) { + return NextResponse.json( + { message: "Geçersiz dosya tipi. Sadece resim dosyaları kabul edilir." }, + { status: 400 } + ); + } + + // Input validation + const widthInput = formData.get("width") as string; + const heightInput = formData.get("height") as string; + const qualityInput = formData.get("quality") as string; + const formatInput = (formData.get("format") as string) || "jpeg"; + + const width = Math.max(1, Math.min(10000, parseInt(widthInput) || 800)); + const height = Math.max(1, Math.min(10000, parseInt(heightInput) || 600)); + const quality = Math.max(1, Math.min(100, parseInt(qualityInput) || 90)); + const allowedFormats = ["jpeg", "jpg", "png", "webp", "avif"]; + const format = allowedFormats.includes(formatInput) ? formatInput : "jpeg"; + + const bytes = await file.arrayBuffer(); + const buffer = Buffer.from(bytes); + + // Resim manipülasyonu - Tam istenen boyuta getir (crop ile, bozmadan) + // fit: "cover" kullanarak resmi tam boyuta getiriyoruz + // Aspect ratio korunur, fazla kısımlar ortadan kesilir (crop) + let processedBuffer = sharp(buffer).resize(width, height, { + fit: "cover", // Tam boyuta getir, aspect ratio koru, fazla kısımları kes + position: "center", // Ortadan crop yap + withoutEnlargement: false, // Gerekirse büyüt de tam boyuta getir + }); + + // Format ve kalite ayarları + const normalizedFormat = format === "jpg" ? "jpeg" : format; + if (normalizedFormat === "jpeg") { + processedBuffer = processedBuffer.jpeg({ quality }); + } else if (normalizedFormat === "png") { + processedBuffer = processedBuffer.png({ quality }); + } else if (normalizedFormat === "webp") { + processedBuffer = processedBuffer.webp({ quality }); + } else if (normalizedFormat === "avif") { + processedBuffer = processedBuffer.avif({ quality }); + } + + const processedImage = await processedBuffer.toBuffer(); + const metadata = await sharp(processedImage).metadata(); + + // Dosya adı oluştur + const fileId = nanoid(); + const originalName = file.name; + const fileExtension = normalizedFormat === "jpeg" ? "jpg" : normalizedFormat; + const fileName = `${fileId}.${fileExtension}`; + + // R2'ye yükle + const contentType = getContentType(fileExtension); + const r2Url = await uploadToR2({ + buffer: processedImage, + fileName, + contentType, + }); + + // Veritabanına kaydet + const imageId = nanoid(); + + await db.insert(images).values({ + id: imageId, + userId, + originalName, + fileName, + filePath: fileName, // R2'de sadece fileName yeterli + url: r2Url, // R2'nin tam URL'si + width: metadata.width || null, + height: metadata.height || null, + quality, + format: normalizedFormat, + fileSize: processedImage.length, + }); + + const fullImageUrl = r2Url; + + return NextResponse.json({ + message: "Resim başarıyla yüklendi", + image: { + id: imageId, + url: fullImageUrl, + width: metadata.width, + height: metadata.height, + }, + }); + } catch (error: any) { + console.error("Upload hatası:", error); + console.error("Error stack:", error?.stack); + console.error("Error message:", error?.message); + + // Production'da detaylı hata mesajı döndür (debug için) + const errorMessage = process.env.NODE_ENV === "production" + ? `Yükleme başarısız: ${error?.message || "Bilinmeyen hata"}` + : "Yükleme başarısız"; + + return NextResponse.json( + { message: errorMessage }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/admin/users/[id]/api-keys/[keyId]/route.ts b/app/api/v1/admin/users/[id]/api-keys/[keyId]/route.ts new file mode 100644 index 0000000..565154b --- /dev/null +++ b/app/api/v1/admin/users/[id]/api-keys/[keyId]/route.ts @@ -0,0 +1,87 @@ +import { NextRequest, NextResponse } from "next/server"; +import { db } from "@/db"; +import { apiKeys } from "@/db/schema"; +import { and, eq } from "drizzle-orm"; +import { authenticateWebOrAPIRequest } from "@/app/lib/api-auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { maskApiKey } from "@/app/lib/jwt"; +import { + expiresAtFromDays, + getDaysRemaining, + getExpiryRemainingLabel, + parseExpiresInDaysOptional, +} from "@/app/lib/api-key-utils"; + +/** + * PATCH /api/v1/admin/users/[id]/api-keys/[keyId] + * + * Body: { "expiresInDays": number | null } + * — null veya 0: süresiz; 1–3650: bugünden itibaren o kadar gün sonra sona erer + */ +export async function PATCH( + request: NextRequest, + context: { params: Promise<{ id: string; keyId: string }> } +) { + const auth = await authenticateWebOrAPIRequest(request); + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error ?? "Yetkisiz" }, { status: 401 }); + } + if (!isAdmin(auth.role!)) { + return NextResponse.json( + { error: "Bu işlem için admin yetkisi gerekir." }, + { status: 403 } + ); + } + + const { id: userId, keyId } = await context.params; + + let body: { expiresInDays?: unknown }; + try { + body = await request.json(); + } catch { + return NextResponse.json({ error: "Geçersiz JSON" }, { status: 400 }); + } + + const parsed = parseExpiresInDaysOptional(body.expiresInDays); + if (!parsed.ok) { + return NextResponse.json({ error: parsed.error }, { status: 400 }); + } + + const expiresAt = + parsed.value === null ? null : expiresAtFromDays(parsed.value); + + const updated = await db + .update(apiKeys) + .set({ expiresAt, updatedAt: new Date() }) + .where(and(eq(apiKeys.id, keyId), eq(apiKeys.userId, userId))) + .returning({ + id: apiKeys.id, + name: apiKeys.name, + key: apiKeys.key, + expiresAt: apiKeys.expiresAt, + isActive: apiKeys.isActive, + }); + + if (updated.length === 0) { + return NextResponse.json( + { error: "Anahtar bulunamadı veya bu kullanıcıya ait değil." }, + { status: 404 } + ); + } + + const r = updated[0]; + const exp = r.expiresAt ?? null; + return NextResponse.json({ + success: true, + message: "API anahtarı süresi güncellendi.", + data: { + id: r.id, + name: r.name, + keyPreview: maskApiKey(r.key), + expiresAt: exp?.toISOString() ?? null, + daysRemaining: getDaysRemaining(exp), + remainingLabel: getExpiryRemainingLabel(exp), + isActive: r.isActive, + }, + }); +} diff --git a/app/api/v1/admin/users/[id]/api-keys/route.ts b/app/api/v1/admin/users/[id]/api-keys/route.ts new file mode 100644 index 0000000..c42fa5b --- /dev/null +++ b/app/api/v1/admin/users/[id]/api-keys/route.ts @@ -0,0 +1,63 @@ +import { NextRequest, NextResponse } from "next/server"; +import { db } from "@/db"; +import { apiKeys } from "@/db/schema"; +import { eq, desc } from "drizzle-orm"; +import { authenticateWebOrAPIRequest } from "@/app/lib/api-auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { maskApiKey } from "@/app/lib/jwt"; +import { getDaysRemaining, getExpiryRemainingLabel } from "@/app/lib/api-key-utils"; + +/** + * GET /api/v1/admin/users/[id]/api-keys — Admin: seçilen kullanıcının API anahtarları + */ +export async function GET( + request: NextRequest, + context: { params: Promise<{ id: string }> } +) { + const auth = await authenticateWebOrAPIRequest(request); + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error ?? "Yetkisiz" }, { status: 401 }); + } + if (!isAdmin(auth.role!)) { + return NextResponse.json( + { error: "Bu işlem için admin yetkisi gerekir." }, + { status: 403 } + ); + } + + const { id: userId } = await context.params; + + const rows = await db + .select({ + id: apiKeys.id, + name: apiKeys.name, + key: apiKeys.key, + expiresAt: apiKeys.expiresAt, + lastUsedAt: apiKeys.lastUsedAt, + isActive: apiKeys.isActive, + createdAt: apiKeys.createdAt, + }) + .from(apiKeys) + .where(eq(apiKeys.userId, userId)) + .orderBy(desc(apiKeys.createdAt)); + + return NextResponse.json({ + success: true, + data: { + keys: rows.map((r) => { + const exp = r.expiresAt ?? null; + return { + id: r.id, + name: r.name, + keyPreview: maskApiKey(r.key), + expiresAt: exp?.toISOString() ?? null, + daysRemaining: getDaysRemaining(exp), + remainingLabel: getExpiryRemainingLabel(exp), + lastUsedAt: r.lastUsedAt?.toISOString() ?? null, + isActive: r.isActive, + createdAt: r.createdAt.toISOString(), + }; + }), + }, + }); +} diff --git a/app/api/v1/admin/users/[id]/role/route.ts b/app/api/v1/admin/users/[id]/role/route.ts new file mode 100644 index 0000000..df6d70a --- /dev/null +++ b/app/api/v1/admin/users/[id]/role/route.ts @@ -0,0 +1,67 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { isAdmin, UserRole, updateUserRole } from "@/app/lib/permissions"; + +/** + * PATCH /api/v1/admin/users/[id]/role + * Kullanıcının rolünü değiştir (Sadece admin) + */ +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + // Admin kontrolü + if (!isAdmin(auth.role!)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler rol değiştirebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + const body = await request.json(); + const { role } = body; + + // Role validasyonu + const validRoles: UserRole[] = ["user", "admin", "moderator"]; + if (!role || !validRoles.includes(role)) { + return NextResponse.json( + { error: "Geçersiz rol. Geçerli roller: user, admin, moderator" }, + { status: 400 } + ); + } + + // Kendi rolünü değiştirmeyi engelle + if (userId === auth.userId) { + return NextResponse.json( + { error: "Kendi rolünüzü değiştiremezsiniz" }, + { status: 400 } + ); + } + + // Rolü güncelle + await updateUserRole(userId, role); + + return NextResponse.json({ + success: true, + message: "Kullanıcı rolü başarıyla güncellendi", + data: { + userId, + newRole: role, + }, + }); + } catch (error: any) { + console.error("Rol güncelleme hatası:", error); + return NextResponse.json( + { error: "Rol güncellenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/admin/users/[id]/route.ts b/app/api/v1/admin/users/[id]/route.ts new file mode 100644 index 0000000..83c3582 --- /dev/null +++ b/app/api/v1/admin/users/[id]/route.ts @@ -0,0 +1,72 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { hasPermission, PERMISSIONS } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user, images, apiKeys } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +/** + * DELETE /api/v1/admin/users/[id] + * Kullanıcıyı sil (Sadece admin) + * Kullanıcının tüm resimleri ve API anahtarları da silinir + */ +export async function DELETE( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + // Permission kontrolü + if (!hasPermission(auth.role!, PERMISSIONS.USER_DELETE)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler kullanıcı silebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + + // Kendi hesabını silmeyi engelle + if (userId === auth.userId) { + return NextResponse.json( + { error: "Kendi hesabınızı silemezsiniz" }, + { status: 400 } + ); + } + + // Kullanıcının var olup olmadığını kontrol et + const targetUser = await db.select().from(user).where(eq(user.id, userId)).limit(1); + if (targetUser.length === 0) { + return NextResponse.json({ error: "Kullanıcı bulunamadı" }, { status: 404 }); + } + + // Kullanıcının resimlerini sil + const deletedImages = await db.delete(images).where(eq(images.userId, userId)); + + // Kullanıcının API anahtarlarını sil + await db.delete(apiKeys).where(eq(apiKeys.userId, userId)); + + // Kullanıcıyı sil + await db.delete(user).where(eq(user.id, userId)); + + return NextResponse.json({ + success: true, + message: "Kullanıcı başarıyla silindi", + data: { + deletedUserId: userId, + deletedUser: targetUser[0].email, + }, + }); + } catch (error: any) { + console.error("Kullanıcı silme hatası:", error); + return NextResponse.json( + { error: "Kullanıcı silinemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/admin/users/[id]/verification/route.ts b/app/api/v1/admin/users/[id]/verification/route.ts new file mode 100644 index 0000000..25dfba8 --- /dev/null +++ b/app/api/v1/admin/users/[id]/verification/route.ts @@ -0,0 +1,69 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +/** + * PATCH /api/v1/admin/users/[id]/verification + * Kullanıcının email doğrulamasını değiştir (Sadece admin - JWT) + */ +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + // Admin kontrolü + if (!isAdmin(auth.role!)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler doğrulama değiştirebilir." }, + { status: 403 } + ); + } + + try { + const { id: userId } = await params; + const body = await request.json(); + const { emailVerified } = body; + + // Boolean validasyonu + if (typeof emailVerified !== "boolean") { + return NextResponse.json( + { error: "emailVerified boolean olmalıdır" }, + { status: 400 } + ); + } + + // Email doğrulama durumunu güncelle + const result = await db + .update(user) + .set({ emailVerified }) + .where(eq(user.id, userId)) + .returning(); + + if (result.length === 0) { + return NextResponse.json({ error: "Kullanıcı bulunamadı" }, { status: 404 }); + } + + return NextResponse.json({ + success: true, + message: `Email doğrulama ${emailVerified ? "aktif edildi" : "pasif edildi"}`, + data: { + userId, + emailVerified, + }, + }); + } catch (error: any) { + console.error("Email doğrulama güncelleme hatası:", error); + return NextResponse.json( + { error: "Email doğrulama güncellenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/admin/users/route.ts b/app/api/v1/admin/users/route.ts new file mode 100644 index 0000000..f98c1e6 --- /dev/null +++ b/app/api/v1/admin/users/route.ts @@ -0,0 +1,54 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { isAdmin } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { user } from "@/db/schema"; +import { desc } from "drizzle-orm"; + +/** + * GET /api/v1/admin/users + * Tüm kullanıcıları listele (Sadece admin) + */ +export async function GET(request: NextRequest) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + // Admin kontrolü + if (!isAdmin(auth.role!)) { + return NextResponse.json( + { error: "Bu işlem için yetkiniz yok. Sadece adminler kullanıcıları görüntüleyebilir." }, + { status: 403 } + ); + } + + try { + const users = await db + .select({ + id: user.id, + name: user.name, + email: user.email, + role: user.role, + emailVerified: user.emailVerified, + createdAt: user.createdAt, + }) + .from(user) + .orderBy(desc(user.createdAt)); + + return NextResponse.json({ + success: true, + data: { + users, + total: users.length, + }, + }); + } catch (error: any) { + console.error("Kullanıcı listesi hatası:", error); + return NextResponse.json( + { error: "Kullanıcılar yüklenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/api-keys/[id]/route.ts b/app/api/v1/api-keys/[id]/route.ts new file mode 100644 index 0000000..b379ab1 --- /dev/null +++ b/app/api/v1/api-keys/[id]/route.ts @@ -0,0 +1,38 @@ +import { NextRequest, NextResponse } from "next/server"; +import { db } from "@/db"; +import { apiKeys } from "@/db/schema"; +import { and, eq } from "drizzle-orm"; +import { authenticateWebOrAPIRequest } from "@/app/lib/api-auth"; + +/** + * DELETE /api/v1/api-keys/[id] — Kendi anahtarını iptal et (isActive: false) + */ +export async function DELETE( + request: NextRequest, + context: { params: Promise<{ id: string }> } +) { + const auth = await authenticateWebOrAPIRequest(request); + if (!auth.authenticated || !auth.userId) { + return NextResponse.json({ error: auth.error ?? "Yetkisiz" }, { status: 401 }); + } + + const { id } = await context.params; + + const updated = await db + .update(apiKeys) + .set({ isActive: false, updatedAt: new Date() }) + .where(and(eq(apiKeys.id, id), eq(apiKeys.userId, auth.userId))) + .returning({ id: apiKeys.id }); + + if (updated.length === 0) { + return NextResponse.json( + { error: "Anahtar bulunamadı veya size ait değil." }, + { status: 404 } + ); + } + + return NextResponse.json({ + success: true, + message: "API anahtarı iptal edildi.", + }); +} diff --git a/app/api/v1/api-keys/route.ts b/app/api/v1/api-keys/route.ts new file mode 100644 index 0000000..f0b5275 --- /dev/null +++ b/app/api/v1/api-keys/route.ts @@ -0,0 +1,121 @@ +import { NextRequest, NextResponse } from "next/server"; +import { nanoid } from "nanoid"; +import { db } from "@/db"; +import { apiKeys } from "@/db/schema"; +import { eq, desc } from "drizzle-orm"; +import { authenticateWebOrAPIRequest } from "@/app/lib/api-auth"; +import { generateAPIKey, maskApiKey } from "@/app/lib/jwt"; +import { + MAX_API_KEY_NAME_LEN, + expiresAtFromDays, + getDaysRemaining, + getExpiryRemainingLabel, + parseExpiresInDaysOptional, +} from "@/app/lib/api-key-utils"; + +/** + * GET /api/v1/api-keys — Oturum veya Bearer ile: kendi API anahtarlarını listele (tam key dönmez) + */ +export async function GET(request: NextRequest) { + const auth = await authenticateWebOrAPIRequest(request); + if (!auth.authenticated || !auth.userId) { + return NextResponse.json({ error: auth.error ?? "Yetkisiz" }, { status: 401 }); + } + + const rows = await db + .select({ + id: apiKeys.id, + name: apiKeys.name, + key: apiKeys.key, + expiresAt: apiKeys.expiresAt, + lastUsedAt: apiKeys.lastUsedAt, + isActive: apiKeys.isActive, + createdAt: apiKeys.createdAt, + }) + .from(apiKeys) + .where(eq(apiKeys.userId, auth.userId)) + .orderBy(desc(apiKeys.createdAt)); + + return NextResponse.json({ + success: true, + data: { + keys: rows.map((r) => { + const exp = r.expiresAt ?? null; + return { + id: r.id, + name: r.name, + keyPreview: maskApiKey(r.key), + expiresAt: exp?.toISOString() ?? null, + daysRemaining: getDaysRemaining(exp), + remainingLabel: getExpiryRemainingLabel(exp), + lastUsedAt: r.lastUsedAt?.toISOString() ?? null, + isActive: r.isActive, + createdAt: r.createdAt.toISOString(), + }; + }), + }, + }); +} + +/** + * POST /api/v1/api-keys — Yeni API anahtarı oluştur (tam key yalnızca bu yanıtta bir kez) + * + * Body: { "name": string, "expiresInDays"?: number | null } + * — expiresInDays yok/null/0: süresiz; 1–3650: bugünden itibaren o kadar gün + */ +export async function POST(request: NextRequest) { + const auth = await authenticateWebOrAPIRequest(request); + if (!auth.authenticated || !auth.userId) { + return NextResponse.json({ error: auth.error ?? "Yetkisiz" }, { status: 401 }); + } + + let body: { name?: unknown; expiresInDays?: unknown }; + try { + body = await request.json(); + } catch { + return NextResponse.json({ error: "Geçersiz JSON" }, { status: 400 }); + } + + const name = typeof body.name === "string" ? body.name.trim() : ""; + if (!name || name.length > MAX_API_KEY_NAME_LEN) { + return NextResponse.json( + { + error: `name zorunludur ve en fazla ${MAX_API_KEY_NAME_LEN} karakter olabilir.`, + }, + { status: 400 } + ); + } + + const parsed = parseExpiresInDaysOptional(body.expiresInDays); + if (!parsed.ok) { + return NextResponse.json({ error: parsed.error }, { status: 400 }); + } + + const expiresAt = + parsed.value === null ? null : expiresAtFromDays(parsed.value); + const plainKey = generateAPIKey(); + const id = nanoid(); + + await db.insert(apiKeys).values({ + id, + userId: auth.userId, + name, + key: plainKey, + expiresAt, + isActive: true, + }); + + return NextResponse.json({ + success: true, + message: + "API anahtarı oluşturuldu. Tam değeri yalnızca bu yanıtta saklayın; bir daha gösterilmez.", + data: { + id, + name, + key: plainKey, + expiresAt: expiresAt?.toISOString() ?? null, + daysRemaining: getDaysRemaining(expiresAt), + remainingLabel: getExpiryRemainingLabel(expiresAt), + }, + }); +} diff --git a/app/api/v1/auth/login/route.ts b/app/api/v1/auth/login/route.ts new file mode 100644 index 0000000..2038901 --- /dev/null +++ b/app/api/v1/auth/login/route.ts @@ -0,0 +1,73 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { signJWT } from "@/app/lib/jwt"; + +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const { email, password } = body; + + // Validasyon + if (!email || !password) { + return NextResponse.json( + { error: "Email ve password gereklidir" }, + { status: 400 } + ); + } + + // Better Auth ile giriş yap + try { + const signInResponse = await auth.api.signInEmail({ + body: { + email, + password, + }, + }); + + if (!signInResponse || !signInResponse.user) { + return NextResponse.json( + { error: "Geçersiz email veya şifre" }, + { status: 401 } + ); + } + + const user = signInResponse.user; + + // JWT token oluştur + const accessToken = signJWT( + { + userId: user.id, + email: user.email, + type: "access", + }, + "7d" + ); + + return NextResponse.json({ + success: true, + message: "Giriş başarılı", + data: { + user: { + id: user.id, + email: user.email, + name: user.name, + }, + accessToken, + }, + }); + } catch (authError: any) { + // Better Auth hatası - muhtemelen geçersiz credentials + console.error("Better Auth login hatası:", authError); + return NextResponse.json( + { error: "Geçersiz email veya şifre" }, + { status: 401 } + ); + } + } catch (error: any) { + console.error("Login API hatası:", error); + return NextResponse.json( + { error: "Giriş sırasında bir hata oluştu" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/auth/register/route.ts b/app/api/v1/auth/register/route.ts new file mode 100644 index 0000000..228a545 --- /dev/null +++ b/app/api/v1/auth/register/route.ts @@ -0,0 +1,80 @@ +import { NextRequest, NextResponse } from "next/server"; +import { auth } from "@/app/lib/auth"; +import { signJWT } from "@/app/lib/jwt"; + +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const { email, password, name } = body; + + // Validasyon + if (!email || !password || !name) { + return NextResponse.json( + { error: "Email, password ve name gereklidir" }, + { status: 400 } + ); + } + + if (password.length < 8) { + return NextResponse.json( + { error: "Şifre en az 8 karakter olmalıdır" }, + { status: 400 } + ); + } + + // Better Auth ile kullanıcı oluştur + try { + const signUpResponse = await auth.api.signUpEmail({ + body: { + email, + password, + name, + }, + }); + + if (!signUpResponse || !signUpResponse.user) { + throw new Error("Kullanıcı oluşturulamadı"); + } + + const user = signUpResponse.user; + + // JWT token oluştur + const accessToken = signJWT( + { + userId: user.id, + email: user.email, + type: "access", + }, + "7d" + ); + + return NextResponse.json({ + success: true, + message: "Kayıt başarılı", + data: { + user: { + id: user.id, + email: user.email, + name: user.name, + }, + accessToken, + }, + }); + } catch (authError: any) { + // Better Auth hatası - muhtemelen email zaten kullanımda + if (authError.message?.includes("exists") || authError.message?.includes("duplicate")) { + return NextResponse.json( + { error: "Bu email adresi zaten kullanımda" }, + { status: 409 } + ); + } + throw authError; + } + } catch (error: any) { + console.error("Register API hatası:", error); + return NextResponse.json( + { error: error.message || "Kayıt sırasında bir hata oluştu" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/images/[id]/route.ts b/app/api/v1/images/[id]/route.ts new file mode 100644 index 0000000..ca8b852 --- /dev/null +++ b/app/api/v1/images/[id]/route.ts @@ -0,0 +1,80 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { hasPermission, PERMISSIONS } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { eq, and } from "drizzle-orm"; +import { deleteFromR2 } from "@/app/lib/r2-storage"; + +/** + * DELETE /api/v1/images/[id] + * Resim sil + * Kullanıcılar sadece kendi resimlerini silebilir + * Moderator ve adminler herhangi bir resmi silebilir + * + * Headers: + * - Authorization: Bearer + */ +export async function DELETE( + request: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + try { + const { id } = await params; + + // Permission kontrolü - moderator ve admin herhangi bir resmi silebilir + const canDeleteAny = hasPermission(auth.role!, PERMISSIONS.IMAGE_DELETE_ANY); + + // Resmi bul + const imageRecords = await db + .select() + .from(images) + .where(eq(images.id, id)) + .limit(1); + + if (imageRecords.length === 0) { + return NextResponse.json( + { error: "Resim bulunamadı" }, + { status: 404 } + ); + } + + const image = imageRecords[0]; + + // Yetki kontrolü - kendi resmi değilse ve delete any yetkisi yoksa reddedilir + if (!canDeleteAny && image.userId !== auth.userId) { + return NextResponse.json( + { error: "Bu resmi silme yetkiniz yok" }, + { status: 403 } + ); + } + + // R2'den dosyayı sil + try { + await deleteFromR2(image.fileName); + } catch (fileError) { + console.error("R2'den silme hatası:", fileError); + // Devam et, veritabanından sil + } + + // Veritabanından sil + await db.delete(images).where(eq(images.id, id)); + + return NextResponse.json({ + success: true, + message: "Resim başarıyla silindi", + }); + } catch (error: any) { + console.error("API - Resim silme hatası:", error); + return NextResponse.json( + { error: "Resim silinemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/images/route.ts b/app/api/v1/images/route.ts new file mode 100644 index 0000000..044d44a --- /dev/null +++ b/app/api/v1/images/route.ts @@ -0,0 +1,67 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import { hasPermission, PERMISSIONS } from "@/app/lib/permissions"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { eq, desc } from "drizzle-orm"; + +/** + * GET /api/v1/images + * Kullanıcının tüm resimlerini listele + * Moderator ve adminler tüm resimleri görebilir + * + * Headers: + * - Authorization: Bearer + */ +export async function GET(request: NextRequest) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + try { + // Permission kontrolü - admin ve moderator tüm resimleri görebilir + const canViewAll = hasPermission(auth.role!, PERMISSIONS.IMAGE_VIEW_ANY); + + let userImages; + if (canViewAll) { + // Tüm resimleri listele + userImages = await db + .select() + .from(images) + .orderBy(desc(images.createdAt)); + } else { + // Sadece kendi resimlerini listele + userImages = await db + .select() + .from(images) + .where(eq(images.userId, auth.userId!)) + .orderBy(desc(images.createdAt)); + } + + return NextResponse.json({ + success: true, + data: { + images: userImages.map((img) => ({ + id: img.id, + originalName: img.originalName, + url: img.url, // R2 URL'leri zaten tam URL olarak kaydedildi + width: img.width, + height: img.height, + quality: img.quality, + format: img.format, + fileSize: img.fileSize, + createdAt: img.createdAt.toISOString(), + })), + total: userImages.length, + }, + }); + } catch (error: any) { + console.error("API - Resim listesi hatası:", error); + return NextResponse.json( + { error: "Resimler yüklenemedi" }, + { status: 500 } + ); + } +} diff --git a/app/api/v1/images/upload/route.ts b/app/api/v1/images/upload/route.ts new file mode 100644 index 0000000..9b31d35 --- /dev/null +++ b/app/api/v1/images/upload/route.ts @@ -0,0 +1,151 @@ +import { NextRequest, NextResponse } from "next/server"; +import { authenticateAPIRequest } from "@/app/lib/api-auth"; +import sharp from "sharp"; +import { db } from "@/db"; +import { images } from "@/db/schema"; +import { nanoid } from "nanoid"; +import { uploadToR2, getContentType } from "@/app/lib/r2-storage"; + +/** + * POST /api/v1/images/upload + * Resim yükle ve manipüle et + * + * Headers: + * - Authorization: Bearer + * - Content-Type: multipart/form-data + * + * Body (FormData): + * - file: Resim dosyası + * - width: Genişlik (px) - opsiyonel, default: 800 + * - height: Yükseklik (px) - opsiyonel, default: 600 + * - quality: Kalite (1-100) - opsiyonel, default: 90 + * - format: Format (jpeg, png, webp, avif) - opsiyonel, default: jpeg + */ +export async function POST(request: NextRequest) { + const auth = await authenticateAPIRequest(request); + + if (!auth.authenticated) { + return NextResponse.json({ error: auth.error }, { status: 401 }); + } + + try { + const formData = await request.formData(); + const file = formData.get("file") as File; + + if (!file) { + return NextResponse.json( + { error: "Dosya bulunamadı" }, + { status: 400 } + ); + } + + // Dosya boyutu kontrolü (max 10MB) + const MAX_FILE_SIZE = 10 * 1024 * 1024; + if (file.size > MAX_FILE_SIZE) { + return NextResponse.json( + { error: "Dosya boyutu çok büyük. Maksimum 10MB olmalıdır." }, + { status: 400 } + ); + } + + // Dosya tipi kontrolü + const allowedMimeTypes = ["image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp", "image/avif"]; + if (!allowedMimeTypes.includes(file.type)) { + return NextResponse.json( + { error: "Geçersiz dosya tipi. Sadece resim dosyaları kabul edilir." }, + { status: 400 } + ); + } + + // Parametreleri al + const widthInput = formData.get("width") as string; + const heightInput = formData.get("height") as string; + const qualityInput = formData.get("quality") as string; + const formatInput = (formData.get("format") as string) || "jpeg"; + + const width = Math.max(1, Math.min(10000, parseInt(widthInput) || 800)); + const height = Math.max(1, Math.min(10000, parseInt(heightInput) || 600)); + const quality = Math.max(1, Math.min(100, parseInt(qualityInput) || 90)); + const allowedFormats = ["jpeg", "jpg", "png", "webp", "avif"]; + const format = allowedFormats.includes(formatInput) ? formatInput : "jpeg"; + + const bytes = await file.arrayBuffer(); + const buffer = Buffer.from(bytes); + + // Resim manipülasyonu + let processedBuffer = sharp(buffer).resize(width, height, { + fit: "cover", + position: "center", + withoutEnlargement: false, + }); + + // Format ve kalite ayarları + const normalizedFormat = format === "jpg" ? "jpeg" : format; + if (normalizedFormat === "jpeg") { + processedBuffer = processedBuffer.jpeg({ quality }); + } else if (normalizedFormat === "png") { + processedBuffer = processedBuffer.png({ quality }); + } else if (normalizedFormat === "webp") { + processedBuffer = processedBuffer.webp({ quality }); + } else if (normalizedFormat === "avif") { + processedBuffer = processedBuffer.avif({ quality }); + } + + const processedImage = await processedBuffer.toBuffer(); + const metadata = await sharp(processedImage).metadata(); + + // Dosya kaydet + const fileId = nanoid(); + const originalName = file.name; + const fileExtension = normalizedFormat === "jpeg" ? "jpg" : normalizedFormat; + const fileName = `${fileId}.${fileExtension}`; + + // R2'ye yükle + const contentType = getContentType(fileExtension); + const r2Url = await uploadToR2({ + buffer: processedImage, + fileName, + contentType, + }); + + // Veritabanına kaydet + const imageId = nanoid(); + + await db.insert(images).values({ + id: imageId, + userId: auth.userId!, + originalName, + fileName, + filePath: fileName, // R2'de sadece fileName yeterli + url: r2Url, // R2'nin tam URL'si + width: metadata.width || null, + height: metadata.height || null, + quality, + format: normalizedFormat, + fileSize: processedImage.length, + }); + + const fullImageUrl = r2Url; + + return NextResponse.json({ + success: true, + message: "Resim başarıyla yüklendi", + data: { + image: { + id: imageId, + url: fullImageUrl, + width: metadata.width, + height: metadata.height, + format: normalizedFormat, + fileSize: processedImage.length, + }, + }, + }); + } catch (error: any) { + console.error("API - Upload hatası:", error); + return NextResponse.json( + { error: error.message || "Yükleme başarısız" }, + { status: 500 } + ); + } +} diff --git a/app/favicon.ico b/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/app/favicon.ico differ diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..a2dc41e --- /dev/null +++ b/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..f7fa87e --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/app/lib/api-auth.ts b/app/lib/api-auth.ts new file mode 100644 index 0000000..a947194 --- /dev/null +++ b/app/lib/api-auth.ts @@ -0,0 +1,214 @@ +import { NextRequest } from "next/server"; +import { db } from "@/db"; +import { apiKeys, user } from "@/db/schema"; +import { eq, and } from "drizzle-orm"; +import { verifyJWT, isValidAPIKeyFormat } from "./jwt"; +import { UserRole } from "./permissions"; +import { auth } from "@/app/lib/auth"; + +export interface AuthenticatedRequest extends NextRequest { + userId?: string; + email?: string; + role?: UserRole; +} + +export interface AuthResult { + authenticated: boolean; + userId?: string; + email?: string; + role?: UserRole; + error?: string; +} + +/** + * API isteklerini doğrula (JWT token veya API key ile) + * + * Kullanım: + * const authResult = await authenticateAPIRequest(request); + * if (!authResult.authenticated) { + * return NextResponse.json({ error: authResult.error }, { status: 401 }); + * } + * const userId = authResult.userId; + */ +/** + * Cookie oturumu (Better Auth) veya Bearer (JWT / API key) ile doğrula. + * Web arayüzünden yapılan isteklerde session; script/istemci için Authorization kullanılır. + */ +export async function authenticateWebOrAPIRequest( + request: NextRequest +): Promise { + const session = await auth.api.getSession({ + headers: request.headers, + }); + + if (session?.user) { + const u = session.user as { id: string }; + try { + const users = await db + .select() + .from(user) + .where(eq(user.id, u.id)) + .limit(1); + + if (users.length === 0) { + return { authenticated: false, error: "Kullanıcı bulunamadı." }; + } + + const userData = users[0]; + return { + authenticated: true, + userId: u.id, + email: userData.email, + role: (userData.role as UserRole) || "user", + }; + } catch (error) { + console.error("Session user lookup error:", error); + return { + authenticated: false, + error: "Kimlik doğrulama sırasında bir hata oluştu.", + }; + } + } + + return authenticateAPIRequest(request); +} + +export async function authenticateAPIRequest(request: NextRequest): Promise { + const authHeader = request.headers.get("authorization"); + + if (!authHeader) { + return { + authenticated: false, + error: "Authorization header eksik. Bearer token veya API key gerekli.", + }; + } + + // Bearer token kontrolü + if (authHeader.startsWith("Bearer ")) { + const token = authHeader.substring(7); + + // JWT token mu yoksa API key mi? + if (isValidAPIKeyFormat(token)) { + // API Key doğrulama + return await validateAPIKey(token); + } else { + // JWT token doğrulama + return await validateJWTToken(token); + } + } + + return { + authenticated: false, + error: "Geçersiz authorization formatı. 'Bearer ' formatında olmalı.", + }; +} + +/** + * JWT token doğrula ve kullanıcı bilgilerini getir + */ +async function validateJWTToken(token: string): Promise { + const payload = verifyJWT(token); + + if (!payload) { + return { + authenticated: false, + error: "Geçersiz veya süresi dolmuş token.", + }; + } + + // Kullanıcı bilgilerini DB'den al (role için) + try { + const users = await db + .select() + .from(user) + .where(eq(user.id, payload.userId)) + .limit(1); + + if (users.length === 0) { + return { + authenticated: false, + error: "Kullanıcı bulunamadı.", + }; + } + + const userData = users[0]; + + return { + authenticated: true, + userId: payload.userId, + email: payload.email, + role: (userData.role as UserRole) || "user", + }; + } catch (error) { + console.error("User lookup error:", error); + return { + authenticated: false, + error: "Kimlik doğrulama sırasında bir hata oluştu.", + }; + } +} + +/** + * API key doğrula (veritabanından kontrol) + */ +async function validateAPIKey(key: string): Promise { + try { + const apiKey = await db + .select() + .from(apiKeys) + .where(and(eq(apiKeys.key, key), eq(apiKeys.isActive, true))) + .limit(1); + + if (apiKey.length === 0) { + return { + authenticated: false, + error: "Geçersiz API key.", + }; + } + + const keyData = apiKey[0]; + + // Süre kontrolü + if (keyData.expiresAt && keyData.expiresAt < new Date()) { + return { + authenticated: false, + error: "API key süresi dolmuş.", + }; + } + + // Kullanıcı bilgilerini al + const users = await db + .select() + .from(user) + .where(eq(user.id, keyData.userId)) + .limit(1); + + if (users.length === 0) { + return { + authenticated: false, + error: "Kullanıcı bulunamadı.", + }; + } + + const userData = users[0]; + + // Son kullanım tarihini güncelle (opsiyonel) + await db + .update(apiKeys) + .set({ lastUsedAt: new Date() }) + .where(eq(apiKeys.id, keyData.id)); + + return { + authenticated: true, + userId: keyData.userId, + email: userData.email, + role: (userData.role as UserRole) || "user", + }; + } catch (error) { + console.error("API key doğrulama hatası:", error); + return { + authenticated: false, + error: "Kimlik doğrulama sırasında bir hata oluştu.", + }; + } +} diff --git a/app/lib/api-key-utils.ts b/app/lib/api-key-utils.ts new file mode 100644 index 0000000..449df65 --- /dev/null +++ b/app/lib/api-key-utils.ts @@ -0,0 +1,51 @@ +/** Kullanıcı/admin API key oluşturma ve güncelleme için ortak süre kuralları */ + +export const MAX_API_KEY_NAME_LEN = 120; +export const MAX_EXPIRES_DAYS = 3650; + +export function expiresAtFromDays(days: number): Date { + return new Date(Date.now() + days * 86_400_000); +} + +/** + * Body'den süre çıkarır: yok/null/0 = süresiz; 1..MAX_EXPIRES_DAYS = o kadar gün. + * Geçersiz sayıda null döner (çağıran 400 verebilir). + */ +export function parseExpiresInDaysOptional( + raw: unknown +): { ok: true; value: number | null } | { ok: false; error: string } { + if (raw === undefined || raw === null) { + return { ok: true, value: null }; + } + if (typeof raw !== "number" || !Number.isFinite(raw)) { + return { ok: false, error: "expiresInDays sayı olmalıdır." }; + } + const d = Math.floor(raw); + if (d === 0) { + return { ok: true, value: null }; + } + if (d < 1 || d > MAX_EXPIRES_DAYS) { + return { + ok: false, + error: `expiresInDays 0 (süresiz) veya 1–${MAX_EXPIRES_DAYS} arası olmalıdır.`, + }; + } + return { ok: true, value: d }; +} + +/** Süresiz: daysRemaining null. Süreli: kalan tam gün sayısı (bitiş anına kadar; dolmuşsa 0). */ +export function getDaysRemaining(expiresAt: Date | null | undefined): number | null { + if (expiresAt == null) return null; + const ms = expiresAt.getTime() - Date.now(); + if (ms <= 0) return 0; + return Math.ceil(ms / 86_400_000); +} + +/** Kullanıcı ve admin arayüzleri için kısa Türkçe ibare */ +export function getExpiryRemainingLabel(expiresAt: Date | null | undefined): string { + if (expiresAt == null) return "Süresiz"; + const d = getDaysRemaining(expiresAt); + if (d === 0) return "Süresi doldu"; + if (d === 1) return "1 gün kaldı"; + return `${d} gün kaldı`; +} diff --git a/app/lib/auth.ts b/app/lib/auth.ts new file mode 100644 index 0000000..0b92817 --- /dev/null +++ b/app/lib/auth.ts @@ -0,0 +1,37 @@ +import { betterAuth } from "better-auth"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; +import { db } from "@/db"; +import * as schema from "@/db/schema"; + +// Validate BETTER_AUTH_SECRET at runtime (not during build) +const secret = process.env.BETTER_AUTH_SECRET; +if (!secret && process.env.NODE_ENV === "production") { + console.warn("WARNING: BETTER_AUTH_SECRET is not set. Authentication will not work properly."); +} + +export const auth = betterAuth({ + database: drizzleAdapter(db, { + provider: "pg", + schema: { + user: schema.user, + session: schema.session, + account: schema.account, + verification: schema.verification, + }, + }), + emailAndPassword: { + enabled: true, + }, + secret: secret || "build-time-secret-key-minimum-32-characters-long-temp", + baseURL: process.env.BETTER_AUTH_URL || "http://localhost:3000", + user: { + additionalFields: { + role: { + type: "string", + defaultValue: "user", + required: false, + input: false, // Don't allow setting role on signup + }, + }, + }, +}); \ No newline at end of file diff --git a/app/lib/jwt.ts b/app/lib/jwt.ts new file mode 100644 index 0000000..5ea1300 --- /dev/null +++ b/app/lib/jwt.ts @@ -0,0 +1,54 @@ +import jwt, { SignOptions } from "jsonwebtoken"; +import { nanoid } from "nanoid"; + +const JWT_SECRET = process.env.JWT_SECRET || process.env.BETTER_AUTH_SECRET || "fallback-secret-key"; +const API_KEY_PREFIX = "img_"; + +export interface JWTPayload { + userId: string; + email: string; + type: "access" | "refresh"; +} + +/** + * JWT token oluştur + * @param payload - Token içeriği + * @param expiresIn - Geçerlilik süresi (örn: "7d", "1h") + */ +export function signJWT(payload: JWTPayload, expiresIn: string | number = "7d"): string { + return jwt.sign(payload, JWT_SECRET, { expiresIn } as SignOptions); +} + +/** + * JWT token doğrula + * @param token - Doğrulanacak token + */ +export function verifyJWT(token: string): JWTPayload | null { + try { + const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload; + return decoded; + } catch (error) { + return null; + } +} + +/** + * API key oluştur + * Formad: img_xxxxxxxxxxxxxxxxxxxxxxxx + */ +export function generateAPIKey(): string { + return `${API_KEY_PREFIX}${nanoid(32)}`; +} + +/** + * API key validasyonu + */ +export function isValidAPIKeyFormat(key: string): boolean { + return key.startsWith(API_KEY_PREFIX) && key.length === 36; // img_ + 32 chars +} + +/** Liste/detay için tam anahtarı göstermez (img_xxxx…yyyy) */ +export function maskApiKey(key: string): string { + if (key.length < 12) return "img_••••"; + return `${key.slice(0, 7)}…${key.slice(-4)}`; +} diff --git a/app/lib/next js beter auth yuklu ve drizze orm y.txt b/app/lib/next js beter auth yuklu ve drizze orm y.txt new file mode 100644 index 0000000..329a867 --- /dev/null +++ b/app/lib/next js beter auth yuklu ve drizze orm y.txt @@ -0,0 +1,15 @@ +next js beter auth yuklu ve drizze orm yuklu posgrsql veritabanı ile entegre edilecek. +drizzle orm ile veritabanına bağlanılacak. +beter auth ile register yapılacak. +beter auth ile giriş yapılacak. +giriş yapıldıktan sonra kullanıcının bilgileri veritabanından alınacak. +kullanıcının bilgileri veritabanından alındıktan sonra kullanıcının bilgileri sayfada görüntülenecek. +birkaç yapilandirma eklendi ama duzgun olmayabilir sen kotrol et ve duzelt + + + + + +sadece login olmus userlerin giris yapabilecegi bir sayfa olacak. ve sayfada resim dosyalri yuklenecek en boy kalite format vs kullnacini verdigi bilgilere gore +resim manipule edilecek ve database ye drizzle orm ile kaydedilecek. +resim url si çıkartilarak download edilebilir ve bir buton ile resmin url si kopyalanabilir. olacak ve bu url ile resim indirilebilir. \ No newline at end of file diff --git a/app/lib/permissions.ts b/app/lib/permissions.ts new file mode 100644 index 0000000..b34a682 --- /dev/null +++ b/app/lib/permissions.ts @@ -0,0 +1,93 @@ +import { db } from "@/db"; +import { user } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +export type UserRole = "user" | "admin" | "moderator"; + +// Permission tanımları +export const PERMISSIONS = { + // Image permissions + IMAGE_UPLOAD: "image:upload", + IMAGE_DELETE_OWN: "image:delete:own", + IMAGE_DELETE_ANY: "image:delete:any", + IMAGE_VIEW_OWN: "image:view:own", + IMAGE_VIEW_ANY: "image:view:any", + + // User permissions + USER_VIEW: "user:view", + USER_EDIT: "user:edit", + USER_DELETE: "user:delete", + USER_MANAGE_ROLES: "user:manage:roles", +} as const; + +// Role'lere göre izinler +export const ROLE_PERMISSIONS: Record = { + user: [ + PERMISSIONS.IMAGE_UPLOAD, + PERMISSIONS.IMAGE_DELETE_OWN, + PERMISSIONS.IMAGE_VIEW_OWN, + ], + moderator: [ + PERMISSIONS.IMAGE_UPLOAD, + PERMISSIONS.IMAGE_DELETE_OWN, + PERMISSIONS.IMAGE_VIEW_OWN, + PERMISSIONS.IMAGE_VIEW_ANY, + PERMISSIONS.USER_VIEW, + ], + admin: Object.values(PERMISSIONS), // Tüm izinler +}; + +/** + * Kullanıcının belirli bir role sahip olup olmadığını kontrol eder + */ +export function hasRole(userRole: UserRole, requiredRole: UserRole | UserRole[]): boolean { + const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole]; + return roles.includes(userRole); +} + +/** + * Kullanıcının belirli bir izne sahip olup olmadığını kontrol eder + */ +export function hasPermission(userRole: UserRole, permission: string): boolean { + const rolePermissions = ROLE_PERMISSIONS[userRole] || []; + return rolePermissions.includes(permission); +} + +/** + * Kullanıcının birden fazla izne sahip olup olmadığını kontrol eder + */ +export function hasPermissions(userRole: UserRole, permissions: string[]): boolean { + return permissions.every(permission => hasPermission(userRole, permission)); +} + +/** + * Kullanıcının en az bir izne sahip olup olmadığını kontrol eder + */ +export function hasAnyPermission(userRole: UserRole, permissions: string[]): boolean { + return permissions.some(permission => hasPermission(userRole, permission)); +} + +/** + * Kullanıcının admin olup olmadığını kontrol eder + */ +export function isAdmin(userRole: UserRole): boolean { + return userRole === "admin"; +} + +/** + * Kullanıcı bilgilerini userId'den alır + */ +export async function getUserById(userId: string) { + const users = await db.select().from(user).where(eq(user.id, userId)).limit(1); + return users[0] || null; +} + +/** + * Kullanıcının rolünü günceller (sadece admin yapabilir) + */ +export async function updateUserRole(userId: string, newRole: UserRole) { + await db.update(user).set({ + role: newRole, + updatedAt: new Date() + }).where(eq(user.id, userId)); +} diff --git a/app/lib/r2-storage.ts b/app/lib/r2-storage.ts new file mode 100644 index 0000000..8dd8321 --- /dev/null +++ b/app/lib/r2-storage.ts @@ -0,0 +1,81 @@ +import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3"; + +// R2 configuration +const R2_ACCOUNT_ID = process.env.R2_ACCOUNT_ID || ""; +const R2_ACCESS_KEY_ID = process.env.R2_ACCESS_KEY_ID || ""; +const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY || ""; +const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME || ""; +const R2_PUBLIC_URL = process.env.R2_PUBLIC_URL || ""; + +// S3 client configuration for Cloudflare R2 +const s3Client = new S3Client({ + region: "auto", + endpoint: `https://${R2_ACCOUNT_ID}.eu.r2.cloudflarestorage.com`, + credentials: { + accessKeyId: R2_ACCESS_KEY_ID, + secretAccessKey: R2_SECRET_ACCESS_KEY, + }, +}); + +export interface UploadOptions { + buffer: Buffer; + fileName: string; + contentType: string; +} + +/** + * Upload a file to R2 + */ +export async function uploadToR2(options: UploadOptions): Promise { + const { buffer, fileName, contentType } = options; + + try { + const command = new PutObjectCommand({ + Bucket: R2_BUCKET_NAME, + Key: fileName, + Body: buffer, + ContentType: contentType, + }); + + await s3Client.send(command); + + // Return the public URL + return `${R2_PUBLIC_URL}/${fileName}`; + } catch (error) { + console.error("R2 upload error:", error); + throw new Error(`R2'ye yükleme başarısız: ${error}`); + } +} + +/** + * Delete a file from R2 + */ +export async function deleteFromR2(fileName: string): Promise { + try { + const command = new DeleteObjectCommand({ + Bucket: R2_BUCKET_NAME, + Key: fileName, + }); + + await s3Client.send(command); + } catch (error) { + console.error("R2 delete error:", error); + throw new Error(`R2'den silme başarısız: ${error}`); + } +} + +/** + * Get content type from file extension + */ +export function getContentType(format: string): string { + const contentTypeMap: Record = { + jpg: "image/jpeg", + jpeg: "image/jpeg", + png: "image/png", + gif: "image/gif", + webp: "image/webp", + avif: "image/avif", + }; + + return contentTypeMap[format] || "application/octet-stream"; +} diff --git a/app/login/page.tsx b/app/login/page.tsx new file mode 100644 index 0000000..a40bfc8 --- /dev/null +++ b/app/login/page.tsx @@ -0,0 +1,142 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; + +export default function LoginPage() { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); + const [registerEnabled, setRegisterEnabled] = useState(true); + const router = useRouter(); + + useEffect(() => { + const checkRegisterEnabled = async () => { + try { + const response = await fetch("/api/config"); + const data = await response.json(); + setRegisterEnabled(data.registerEnabled); + } catch (error) { + console.error("Config kontrolü başarısız:", error); + } + }; + + checkRegisterEnabled(); + }, []); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + setLoading(true); + + try { + const response = await fetch("/api/auth/sign-in/email", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + credentials: "include", + body: JSON.stringify({ + email, + password, + }), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.message || "Giriş başarısız"); + } + + router.push("/profile"); + router.refresh(); + } catch (err: any) { + setError(err.message || "Bir hata oluştu"); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+

+ Giriş Yap +

+
+
+ {error && ( +
+ {error} +
+ )} +
+
+ + setEmail(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="ornek@email.com" + /> +
+
+ + setPassword(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="••••••••" + /> +
+
+ +
+ +
+ + {registerEnabled && ( +
+ + Hesabınız yok mu?{" "} + + + Kayıt Ol + +
+ )} +
+
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..88fffda --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,293 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; + +export default function Home() { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [registerEnabled, setRegisterEnabled] = useState(true); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const checkAuth = async () => { + try { + const [authResponse, configResponse] = await Promise.all([ + fetch("/api/auth/get-session", { + credentials: "include", + }), + fetch("/api/config"), + ]); + + const authData = await authResponse.json(); + const configData = await configResponse.json(); + + setIsAuthenticated(!!authData.user); + setRegisterEnabled(configData.registerEnabled); + } catch (error) { + setIsAuthenticated(false); + setRegisterEnabled(true); + } finally { + setLoading(false); + } + }; + + checkAuth(); + }, []); + + if (loading) { + return ( +
+
+
+
+ Yükleniyor... +
+
+
+ ); + } + + return ( +
+ {/* Hero Section */} +
+
+ {/* Main Content */} +
+ {/* Icon/Logo */} +
+
+ + + +
+
+ + {/* Title */} +

+ Image Manipulation API +

+ + {/* Description */} +

+ Resimlerinizi yükleyin, boyutlandırın, formatını değiştirin ve + istediğiniz kalitede kaydedin. +

+

+ JWT API desteği ile dış uygulamalarınızdan da kullanabilirsiniz. +

+ + {/* Features */} +
+
+
+
+ + + +
+
+

+ Hızlı İşlem +

+

+ Saniyeler içinde resim manipülasyonu +

+
+ +
+
+
+ + + +
+
+

+ Çoklu Format +

+

+ JPEG, PNG, WebP, AVIF desteği +

+
+ +
+
+
+ + + +
+
+

+ Güvenli API +

+

+ JWT token ile korumalı erişim +

+
+
+ + {/* CTA Buttons */} +
+ {isAuthenticated ? ( + <> + + + + + Resim Yükle + + + + + + Profilim + + + + + + Admin Panel + + + ) : ( + <> + + Giriş Yap + + + + + {registerEnabled && ( + + Kayıt Ol + + )} + + )} +
+ + {/* API Link */} +
+ + + + + API Dokümantasyonu + +
+
+
+
+
+ ); +} diff --git a/app/profile/page.tsx b/app/profile/page.tsx new file mode 100644 index 0000000..dc7d3dc --- /dev/null +++ b/app/profile/page.tsx @@ -0,0 +1,391 @@ +"use client"; + +import { useEffect, useState, useCallback } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; + +interface User { + id: string; + name: string; + email: string; + emailVerified: boolean; + image: string | null; + createdAt: string; + updatedAt: string; +} + +interface ApiKeyRow { + id: string; + name: string; + keyPreview: string; + expiresAt: string | null; + daysRemaining: number | null; + remainingLabel: string; + lastUsedAt: string | null; + isActive: boolean; + createdAt: string; +} + +export default function ProfilePage() { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + const [apiKeys, setApiKeys] = useState([]); + const [keysLoading, setKeysLoading] = useState(false); + const [newKeyName, setNewKeyName] = useState(""); + const [newKeyDays, setNewKeyDays] = useState(""); + const [createBusy, setCreateBusy] = useState(false); + const router = useRouter(); + + const loadApiKeys = useCallback(async () => { + setKeysLoading(true); + try { + const res = await fetch("/api/v1/api-keys", { credentials: "include" }); + const json = await res.json(); + if (res.ok && json.data?.keys) { + setApiKeys(json.data.keys); + } + } catch { + /* ignore */ + } finally { + setKeysLoading(false); + } + }, []); + + useEffect(() => { + const fetchUser = async () => { + try { + const response = await fetch("/api/auth/get-session", { + credentials: "include", + }); + const data = await response.json(); + + if (!response.ok || !data.user) { + router.push("/login"); + return; + } + + setUser(data.user); + } catch (error) { + console.error("Kullanıcı bilgileri alınamadı:", error); + router.push("/login"); + } finally { + setLoading(false); + } + }; + + fetchUser(); + }, [router]); + + useEffect(() => { + if (user) { + loadApiKeys(); + } + }, [user, loadApiKeys]); + + const createApiKey = async () => { + const name = newKeyName.trim(); + if (!name) return; + setCreateBusy(true); + try { + const body: { name: string; expiresInDays?: number | null } = { name }; + const d = newKeyDays.trim(); + if (d !== "") { + const n = parseInt(d, 10); + if (!Number.isFinite(n) || n < 0) { + alert("Geçerli bir gün sayısı girin veya boş bırakın (süresiz)."); + setCreateBusy(false); + return; + } + body.expiresInDays = n === 0 ? null : n; + } + const res = await fetch("/api/v1/api-keys", { + method: "POST", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + const json = await res.json(); + if (!res.ok) { + alert(json.error || "Oluşturulamadı"); + return; + } + const raw = json.data?.key as string | undefined; + const rem = json.data?.remainingLabel as string | undefined; + if (raw) { + await navigator.clipboard.writeText(raw).catch(() => {}); + const extra = rem ? ` Süre: ${rem}.` : ""; + alert( + `API anahtarı oluşturuldu ve panoya kopyalandı. Bu tam değeri yalnızca bir kez görebilirsiniz.${extra}` + ); + } + setNewKeyName(""); + setNewKeyDays(""); + await loadApiKeys(); + } finally { + setCreateBusy(false); + } + }; + + const revokeKey = async (id: string) => { + if (!confirm("Bu API anahtarını iptal etmek istediğinize emin misiniz?")) return; + const res = await fetch(`/api/v1/api-keys/${id}`, { + method: "DELETE", + credentials: "include", + }); + if (!res.ok) { + const j = await res.json(); + alert(j.error || "İptal edilemedi"); + return; + } + await loadApiKeys(); + }; + + const handleLogout = async () => { + try { + await fetch("/api/auth/sign-out", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + credentials: "include", + body: JSON.stringify({}), + }); + router.push("/login"); + router.refresh(); + } catch (error) { + console.error("Çıkış yapılamadı:", error); + } + }; + + if (loading) { + return ( +
+
+ Yükleniyor... +
+
+ ); + } + + if (!user) { + return null; + } + + return ( +
+
+
+
+

+ Kullanıcı Bilgileri +

+
+ + Resim Yükle + + + Ana Sayfa + + +
+
+ +
+
+

+ Profil Bilgileri +

+
+
+
+ Ad Soyad +
+
+ {user.name} +
+
+
+
+ E-posta +
+
+ {user.email} +
+
+
+
+ E-posta Doğrulandı mı? +
+
+ {user.emailVerified ? ( + + Evet + + ) : ( + + Hayır + + )} +
+
+
+
+ Kullanıcı ID +
+
+ {user.id} +
+
+
+
+ Kayıt Tarihi +
+
+ {new Date(user.createdAt).toLocaleString("tr-TR")} +
+
+
+
+ Son Güncelleme +
+
+ {new Date(user.updatedAt).toLocaleString("tr-TR")} +
+
+
+
+ +
+

+ API anahtarları +

+

+ Resim API'sine JWT yerine{" "} + + Authorization: Bearer img_… + {" "} + ile erişin. Anahtarı burada oluşturun; süre kısıtı opsiyoneldir (boş + = süresiz). Admin gerekirse süreyi değiştirebilir. +

+ +
+
+ + setNewKeyName(e.target.value)} + placeholder="örn. Mobil uygulama" + className="w-full rounded border border-gray-300 bg-white px-3 py-2 text-black dark:border-zinc-600 dark:bg-zinc-900 dark:text-zinc-50" + /> +
+
+ + setNewKeyDays(e.target.value)} + className="w-full rounded border border-gray-300 bg-white px-3 py-2 text-black dark:border-zinc-600 dark:bg-zinc-900 dark:text-zinc-50" + /> +
+ +
+ + {keysLoading ? ( +

Anahtarlar yükleniyor…

+ ) : apiKeys.length === 0 ? ( +

Henüz API anahtarı yok.

+ ) : ( +
+ + + + + + + + + + + + {apiKeys.map((k) => ( + + + + + + + + + ))} + +
İsimÖnizlemeBitiş tarihiKalan süreDurum +
{k.name}{k.keyPreview} + {k.expiresAt + ? new Date(k.expiresAt).toLocaleString("tr-TR") + : "—"} + + + {k.remainingLabel} + + + {k.isActive ? ( + Aktif + ) : ( + İptal + )} + + {k.isActive && ( + + )} +
+
+ )} +
+
+
+
+
+ ); +} diff --git a/app/register/page.tsx b/app/register/page.tsx new file mode 100644 index 0000000..ce4a842 --- /dev/null +++ b/app/register/page.tsx @@ -0,0 +1,211 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; + +export default function RegisterPage() { + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); + const [registerEnabled, setRegisterEnabled] = useState(true); + const [checking, setChecking] = useState(true); + const router = useRouter(); + + useEffect(() => { + const checkRegisterEnabled = async () => { + try { + const response = await fetch("/api/config"); + const data = await response.json(); + setRegisterEnabled(data.registerEnabled); + if (!data.registerEnabled) { + router.push("/login"); + } + } catch (error) { + console.error("Config kontrolü başarısız:", error); + } finally { + setChecking(false); + } + }; + + checkRegisterEnabled(); + }, [router]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + + // Şifre kontrolü + if (password !== confirmPassword) { + setError("Şifreler eşleşmiyor"); + return; + } + + if (password.length < 6) { + setError("Şifre en az 6 karakter olmalıdır"); + return; + } + + setLoading(true); + + try { + const response = await fetch("/api/auth/sign-up/email", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + credentials: "include", + body: JSON.stringify({ + name, + email, + password, + }), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.message || "Kayıt başarısız"); + } + + router.push("/profile"); + router.refresh(); + } catch (err: any) { + setError(err.message || "Bir hata oluştu"); + } finally { + setLoading(false); + } + }; + + if (checking) { + return ( +
+
+ Yükleniyor... +
+
+ ); + } + + if (!registerEnabled) { + return null; + } + + return ( +
+
+
+

+ Kayıt Ol +

+
+
+ {error && ( +
+ {error} +
+ )} +
+
+ + setName(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="Adınız Soyadınız" + /> +
+
+ + setEmail(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="ornek@email.com" + /> +
+
+ + setPassword(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="••••••••" + /> +
+
+ + setConfirmPassword(e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + placeholder="••••••••" + /> +
+
+ +
+ +
+ +
+ + Zaten hesabınız var mı?{" "} + + + Giriş Yap + +
+
+
+
+ ); +} diff --git a/app/upload/page.tsx b/app/upload/page.tsx new file mode 100644 index 0000000..5e02fb7 --- /dev/null +++ b/app/upload/page.tsx @@ -0,0 +1,415 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; +import Swal from "sweetalert2"; + +interface Image { + id: string; + originalName: string; + url: string; + width: number | null; + height: number | null; + quality: number | null; + format: string; + fileSize: number; + createdAt: string; +} + +export default function UploadPage() { + const [file, setFile] = useState(null); + const [width, setWidth] = useState(800); + const [height, setHeight] = useState(600); + + const handleFileChange = (e: React.ChangeEvent) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) { + setFile(selectedFile); + + // Resmin boyutlarını al + const img = new Image(); + const objectUrl = URL.createObjectURL(selectedFile); + + img.onload = () => { + setWidth(img.naturalWidth); + setHeight(img.naturalHeight); + URL.revokeObjectURL(objectUrl); + }; + + img.src = objectUrl; + } + }; + const [quality, setQuality] = useState(90); + const [format, setFormat] = useState("avif"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [success, setSuccess] = useState(""); + const [images, setImages] = useState([]); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [checkingAuth, setCheckingAuth] = useState(true); + const router = useRouter(); + + useEffect(() => { + const checkAuth = async () => { + try { + const response = await fetch("/api/auth/get-session", { + credentials: "include", + }); + const data = await response.json(); + + if (!response.ok || !data.user) { + router.push("/login"); + return; + } + + setIsAuthenticated(true); + loadImages(); + } catch (error) { + console.error("Auth kontrolü başarısız:", error); + router.push("/login"); + } finally { + setCheckingAuth(false); + } + }; + + checkAuth(); + }, [router]); + + const loadImages = async () => { + try { + const response = await fetch("/api/images", { + credentials: "include", + cache: 'no-store', // Cache'i devre dışı bırak + }); + if (response.ok) { + const data = await response.json(); + console.log("Yüklenen resimler:", data.images?.length || 0); + setImages(data.images || []); + } else { + console.error("Resimler yüklenemedi, status:", response.status); + } + } catch (error) { + console.error("Resimler yüklenemedi:", error); + } + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + setSuccess(""); + + if (!file) { + setError("Lütfen bir dosya seçin"); + return; + } + + setLoading(true); + + try { + const formData = new FormData(); + formData.append("file", file); + formData.append("width", width.toString()); + formData.append("height", height.toString()); + formData.append("quality", quality.toString()); + formData.append("format", format); + + const response = await fetch("/api/images/upload", { + method: "POST", + credentials: "include", + body: formData, + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.message || "Yükleme başarısız"); + } + + // Formu tamamen resetle + setSuccess("Resim başarıyla yüklendi!"); + setFile(null); + const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement; + if (fileInput) { + fileInput.value = ''; + } + + // Resimleri yeniden yükle + await loadImages(); + + // Success mesajını kısa süre sonra temizle + setTimeout(() => setSuccess(""), 3000); + } catch (err: any) { + setError(err.message || "Bir hata oluştu"); + } finally { + setLoading(false); + } + }; + + const copyToClipboard = (url: string) => { + navigator.clipboard.writeText(url); + setSuccess("URL kopyalandı!"); + setTimeout(() => setSuccess(""), 2000); + }; + + const downloadImage = (url: string, originalName: string) => { + const link = document.createElement("a"); + link.href = url; + link.download = originalName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + + const handleDelete = async (imageId: string, originalName: string) => { + const result = await Swal.fire({ + title: "Emin misiniz?", + text: `${originalName} adlı resmi silmek istediğinize emin misiniz?`, + icon: "warning", + showCancelButton: true, + confirmButtonColor: "#d33", + cancelButtonColor: "#3085d6", + confirmButtonText: "Evet, Sil!", + cancelButtonText: "İptal", + }); + + if (result.isConfirmed) { + try { + console.log("Silme isteği gönderiliyor, imageId:", imageId); + console.log("Image objesi:", images.find(img => img.id === imageId)); + const response = await fetch(`/api/images/${encodeURIComponent(imageId)}`, { + method: "DELETE", + credentials: "include", + }); + + const data = await response.json(); + + if (!response.ok) { + console.error("Silme hatası:", data); + throw new Error(data.message || "Silme işlemi başarısız"); + } + + Swal.fire("Silindi!", "Resim başarıyla silindi.", "success"); + loadImages(); + } catch (error: any) { + console.error("Silme hatası:", error); + Swal.fire("Hata!", error.message || "Resim silinirken bir hata oluştu.", "error"); + } + } + }; + + if (checkingAuth) { + return ( +
+
+ Yükleniyor... +
+
+ ); + } + + if (!isAuthenticated) { + return null; + } + + return ( +
+
+
+

+ Resim Yükle ve Manipüle Et +

+
+ + Profil + + + Ana Sayfa + +
+
+ +
+ {/* Upload Form */} +
+

+ Resim Yükle +

+
+ {error && ( +
+ {error} +
+ )} + {success && ( +
+ {success} +
+ )} + +
+ + +
+ +
+
+ + setWidth(parseInt(e.target.value) || 800)} + min="1" + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + /> +
+
+ + setHeight(parseInt(e.target.value) || 600)} + min="1" + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + /> +
+
+ +
+ + setQuality(parseInt(e.target.value) || 90)} + min="1" + max="100" + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-blue-500 dark:border-gray-600 dark:bg-zinc-800 dark:text-white" + /> +
+ +
+ + +
+ + +
+
+ + {/* Images List */} +
+

+ Yüklenen Resimler ({images.length}) +

+ {images.length === 0 ? ( +
+

+ Henüz resim yüklenmedi +

+
+ ) : ( +
+ {images.map((image) => ( +
+
+ {image.originalName} +
+
+
+

+ {image.originalName} +

+
+

+ Boyut: {image.width} × {image.height} px +

+

+ Format: {image.format.toUpperCase()} +

+

+ Dosya: {Math.round(image.fileSize / 1024)} KB +

+ {image.quality && ( +

+ Kalite: {image.quality}% +

+ )} +
+
+ + +
+ +
+
+ ))} +
+ )} +
+
+
+
+ ); +} diff --git a/app/uploads/[...path]/route.ts b/app/uploads/[...path]/route.ts new file mode 100644 index 0000000..4367383 --- /dev/null +++ b/app/uploads/[...path]/route.ts @@ -0,0 +1,43 @@ +import { NextRequest, NextResponse } from "next/server"; +import { readFile } from "fs/promises"; +import { join } from "path"; + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ path: string[] }> } +) { + try { + const { path } = await params; + const filePath = join(process.cwd(), "public", "uploads", ...path); + const fileBuffer = await readFile(filePath); + + // Dosya uzantısına göre content-type belirle + const fileName = path[path.length - 1]; + const ext = fileName.split('.').pop()?.toLowerCase(); + + const contentTypeMap: Record = { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'gif': 'image/gif', + 'webp': 'image/webp', + 'avif': 'image/avif', + 'svg': 'image/svg+xml', + }; + + const contentType = contentTypeMap[ext || ''] || 'application/octet-stream'; + + return new NextResponse(fileBuffer, { + headers: { + 'Content-Type': contentType, + 'Cache-Control': 'public, max-age=31536000, immutable', + }, + }); + } catch (error) { + console.error('Dosya okuma hatası:', error); + return NextResponse.json( + { message: "Dosya bulunamadı" }, + { status: 404 } + ); + } +} diff --git a/db.ts b/db.ts new file mode 100644 index 0000000..775de32 --- /dev/null +++ b/db.ts @@ -0,0 +1,27 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; +import * as dotenv from "dotenv"; + +dotenv.config(); + +// Create pool - DATABASE_URL check will happen at runtime when pool is actually used +// During build time, this won't fail even if DATABASE_URL is not set +const pool = new Pool({ + connectionString: process.env.DATABASE_URL || "postgresql://localhost:5432/temp", + max: 20, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 10000, + ssl: process.env.DATABASE_SSL === "true" ? { rejectUnauthorized: false } : false, +}); + +// Test connection on startup +pool.on("error", (err) => { + console.error("Unexpected error on idle client", err); +}); + +// Validate DATABASE_URL at runtime (not during build) +if (process.env.NODE_ENV === "production" && !process.env.DATABASE_URL) { + console.warn("WARNING: DATABASE_URL is not set. Database operations will fail."); +} + +export const db = drizzle(pool); diff --git a/db/schema.ts b/db/schema.ts new file mode 100644 index 0000000..e9090fb --- /dev/null +++ b/db/schema.ts @@ -0,0 +1,90 @@ +import { pgTable, text, timestamp, boolean, integer } from "drizzle-orm/pg-core"; + +// Roles enum +export const roleEnum = ["user", "admin", "moderator"] as const; +export type UserRole = typeof roleEnum[number]; + +// Better-auth requires these tables +export const user = pgTable("user", { + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("emailVerified").notNull().default(false), + image: text("image"), + role: text("role").notNull().default("user"), // user, admin, moderator + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), +}); + +export const session = pgTable("session", { + id: text("id").primaryKey(), + expiresAt: timestamp("expiresAt").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), + ipAddress: text("ipAddress"), + userAgent: text("userAgent"), + userId: text("userId") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), +}); + +export const account = pgTable("account", { + id: text("id").primaryKey(), + accountId: text("accountId").notNull(), + providerId: text("providerId").notNull(), + userId: text("userId") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + accessToken: text("accessToken"), + refreshToken: text("refreshToken"), + idToken: text("idToken"), + accessTokenExpiresAt: timestamp("accessTokenExpiresAt"), + refreshTokenExpiresAt: timestamp("refreshTokenExpiresAt"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), +}); + +export const verification = pgTable("verification", { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expiresAt").notNull(), + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), +}); + +export const images = pgTable("images", { + id: text("id").primaryKey(), + userId: text("userId") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + originalName: text("originalName").notNull(), + fileName: text("fileName").notNull(), + filePath: text("filePath").notNull(), + url: text("url").notNull(), + width: integer("width"), + height: integer("height"), + quality: integer("quality"), + format: text("format").notNull(), + fileSize: integer("fileSize").notNull(), + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), +}); + +// API Keys for external applications +export const apiKeys = pgTable("apiKeys", { + id: text("id").primaryKey(), + userId: text("userId") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + name: text("name").notNull(), // API key ismi (örn: "Mobile App", "Dashboard") + key: text("key").notNull().unique(), // API key + lastUsedAt: timestamp("lastUsedAt"), + expiresAt: timestamp("expiresAt"), // null = süresiz + isActive: boolean("isActive").notNull().default(true), + createdAt: timestamp("createdAt").notNull().defaultNow(), + updatedAt: timestamp("updatedAt").notNull().defaultNow(), +}); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..15f9270 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +services: + image-apiv2: + build: + context: . + dockerfile: Dockerfile + container_name: image-apiv2 + user: "1001:1001" # nextjs user (uid:gid) + ports: + - "3151:3000" + networks: + - dokploy-network + environment: + - DATABASE_URL=${DATABASE_URL} + - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} + - BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000} + - REGISTER_ENABLE=${REGISTER_ENABLE:-true} + - R2_ACCOUNT_ID=${R2_ACCOUNT_ID} + - R2_ACCESS_KEY_ID=${R2_ACCESS_KEY_ID} + - R2_SECRET_ACCESS_KEY=${R2_SECRET_ACCESS_KEY} + - R2_BUCKET_NAME=${R2_BUCKET_NAME} + - R2_PUBLIC_URL=${R2_PUBLIC_URL} + - NODE_ENV=production + volumes: + # Uploads klasörünü persist et + - uploads_data:/app/public/uploads + restart: unless-stopped +volumes: + uploads_data: +networks: + dokploy-network: + external: true + # Opsiyonel: PostgreSQL ile birlikte kullanmak için + # depends_on: + # - postgres + + # Opsiyonel: PostgreSQL veritabanı + # postgres: + # image: postgres:16-alpine + # container_name: image-api-db + # environment: + # - POSTGRES_USER=${POSTGRES_USER:-postgres} + # - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} + # - POSTGRES_DB=${POSTGRES_DB:-image_api} + # volumes: + # - postgres_data:/var/lib/postgresql/data + # ports: + # - "5432:5432" + # restart: unless-stopped + +# volumes: +# postgres_data: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..5179f7a --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +# Uploads klasörünü oluştur ve izinleri ayarla (volume mount için) +mkdir -p /app/public/uploads +chmod -R 775 /app/public/uploads + +# Uygulamayı başlat +exec node server.js diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..c746e51 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "drizzle-kit"; +import * as dotenv from "dotenv"; + +dotenv.config(); + +export default defineConfig({ + schema: "./db/schema.ts", + out: "./drizzle", + dialect: "postgresql", + dbCredentials: { + url: process.env.DATABASE_URL!, + }, +}); diff --git a/drizzle/0000_perpetual_alice.sql b/drizzle/0000_perpetual_alice.sql new file mode 100644 index 0000000..fdaad5e --- /dev/null +++ b/drizzle/0000_perpetual_alice.sql @@ -0,0 +1,81 @@ +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "accountId" text NOT NULL, + "providerId" text NOT NULL, + "userId" text NOT NULL, + "accessToken" text, + "refreshToken" text, + "idToken" text, + "accessTokenExpiresAt" timestamp, + "refreshTokenExpiresAt" timestamp, + "scope" text, + "password" text, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "apiKeys" ( + "id" text PRIMARY KEY NOT NULL, + "userId" text NOT NULL, + "name" text NOT NULL, + "key" text NOT NULL, + "lastUsedAt" timestamp, + "expiresAt" timestamp, + "isActive" boolean DEFAULT true NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "apiKeys_key_unique" UNIQUE("key") +); +--> statement-breakpoint +CREATE TABLE "images" ( + "id" text PRIMARY KEY NOT NULL, + "userId" text NOT NULL, + "originalName" text NOT NULL, + "fileName" text NOT NULL, + "filePath" text NOT NULL, + "url" text NOT NULL, + "width" integer, + "height" integer, + "quality" integer, + "format" text NOT NULL, + "fileSize" integer NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "session" ( + "id" text PRIMARY KEY NOT NULL, + "expiresAt" timestamp NOT NULL, + "token" text NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "ipAddress" text, + "userAgent" text, + "userId" text NOT NULL, + CONSTRAINT "session_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE "user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "emailVerified" boolean DEFAULT false NOT NULL, + "image" text, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expiresAt" timestamp NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "apiKeys" ADD CONSTRAINT "apiKeys_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "images" ADD CONSTRAINT "images_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "session" ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/drizzle/0001_harsh_morbius.sql b/drizzle/0001_harsh_morbius.sql new file mode 100644 index 0000000..68b3048 --- /dev/null +++ b/drizzle/0001_harsh_morbius.sql @@ -0,0 +1 @@ +ALTER TABLE "user" ADD COLUMN "role" text DEFAULT 'user' NOT NULL; \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..673fd93 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,527 @@ +{ + "id": "e57a66f4-9087-4f42-843d-86044c7d703b", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idToken": { + "name": "idToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessTokenExpiresAt": { + "name": "accessTokenExpiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refreshTokenExpiresAt": { + "name": "refreshTokenExpiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apiKeys": { + "name": "apiKeys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "apiKeys_userId_user_id_fk": { + "name": "apiKeys_userId_user_id_fk", + "tableFrom": "apiKeys", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKeys_key_unique": { + "name": "apiKeys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.images": { + "name": "images", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "originalName": { + "name": "originalName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fileName": { + "name": "fileName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "quality": { + "name": "quality", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fileSize": { + "name": "fileSize", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "images_userId_user_id_fk": { + "name": "images_userId_user_id_fk", + "tableFrom": "images", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..0085c69 --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,534 @@ +{ + "id": "fc4f3c3d-f7b9-4e17-b7dc-88e2944f9303", + "prevId": "e57a66f4-9087-4f42-843d-86044c7d703b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idToken": { + "name": "idToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessTokenExpiresAt": { + "name": "accessTokenExpiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refreshTokenExpiresAt": { + "name": "refreshTokenExpiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apiKeys": { + "name": "apiKeys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "apiKeys_userId_user_id_fk": { + "name": "apiKeys_userId_user_id_fk", + "tableFrom": "apiKeys", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKeys_key_unique": { + "name": "apiKeys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.images": { + "name": "images", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "originalName": { + "name": "originalName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fileName": { + "name": "fileName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "quality": { + "name": "quality", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fileSize": { + "name": "fileSize", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "images_userId_user_id_fk": { + "name": "images_userId_user_id_fk", + "tableFrom": "images", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..b0e907f --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1767680035227, + "tag": "0000_perpetual_alice", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1767682768043, + "tag": "0001_harsh_morbius", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/image_api.sql b/image_api.sql new file mode 100644 index 0000000..7ac2862 Binary files /dev/null and b/image_api.sql differ diff --git a/make-admin.ts b/make-admin.ts new file mode 100644 index 0000000..08542d9 --- /dev/null +++ b/make-admin.ts @@ -0,0 +1,35 @@ +// Admin kullanıcı oluşturma scripti +import { db } from "./db"; +import { user } from "./db/schema"; +import { eq } from "drizzle-orm"; + +async function makeAdmin() { + const email = process.argv[2]; + + if (!email) { + console.error("Kullanım: tsx make-admin.mjs email@example.com"); + process.exit(1); + } + + try { + const result = await db + .update(user) + .set({ role: "admin" }) + .where(eq(user.email, email)) + .returning(); + + if (result.length === 0) { + console.error(`❌ ${email} bulunamadı`); + process.exit(1); + } + + console.log(`✅ ${email} artık admin!`); + console.log(result[0]); + process.exit(0); + } catch (error: any) { + console.error("Hata:", error.message); + process.exit(1); + } +} + +makeAdmin(); diff --git a/nemoriebank.md b/nemoriebank.md new file mode 100644 index 0000000..e6be63d --- /dev/null +++ b/nemoriebank.md @@ -0,0 +1,115 @@ +# Cline's Memory Bank + +I am Cline, an expert software engineer with a unique characteristic: my memory resets completely between sessions. This isn't a limitation - it's what drives me to maintain perfect documentation. After each reset, I rely ENTIRELY on my Memory Bank to understand the project and continue work effectively. I MUST read ALL memory bank files at the start of EVERY task - this is not optional. + +## Memory Bank Structure + +The Memory Bank consists of core files and optional context files, all in Markdown format. Files build upon each other in a clear hierarchy: + +flowchart TD + PB[projectbrief.md] --> PC[productContext.md] + PB --> SP[systemPatterns.md] + PB --> TC[techContext.md] + + PC --> AC[activeContext.md] + SP --> AC + TC --> AC + + AC --> P[progress.md] + +### Core Files (Required) +1. `projectbrief.md` + - Foundation document that shapes all other files + - Created at project start if it doesn't exist + - Defines core requirements and goals + - Source of truth for project scope + +2. `productContext.md` + - Why this project exists + - Problems it solves + - How it should work + - User experience goals + +3. `activeContext.md` + - Current work focus + - Recent changes + - Next steps + - Active decisions and considerations + - Important patterns and preferences + - Learnings and project insights + +4. `systemPatterns.md` + - System architecture + - Key technical decisions + - Design patterns in use + - Component relationships + - Critical implementation paths + +5. `techContext.md` + - Technologies used + - Development setup + - Technical constraints + - Dependencies + - Tool usage patterns + +6. `progress.md` + - What works + - What's left to build + - Current status + - Known issues + - Evolution of project decisions + +### Additional Context +Create additional files/folders within memory-bank/ when they help organize: +- Complex feature documentation +- Integration specifications +- API documentation +- Testing strategies +- Deployment procedures + +## Core Workflows + +### Plan Mode +flowchart TD + Start[Start] --> ReadFiles[Read Memory Bank] + ReadFiles --> CheckFiles{Files Complete?} + + CheckFiles -->|No| Plan[Create Plan] + Plan --> Document[Document in Chat] + + CheckFiles -->|Yes| Verify[Verify Context] + Verify --> Strategy[Develop Strategy] + Strategy --> Present[Present Approach] + +### Act Mode +flowchart TD + Start[Start] --> Context[Check Memory Bank] + Context --> Update[Update Documentation] + Update --> Execute[Execute Task] + Execute --> Document[Document Changes] + +## Documentation Updates + +Memory Bank updates occur when: +1. Discovering new project patterns +2. After implementing significant changes +3. When user requests with **update memory bank** (MUST review ALL files) +4. When context needs clarification + +flowchart TD + Start[Update Process] + + subgraph Process + P1[Review ALL Files] + P2[Document Current State] + P3[Clarify Next Steps] + P4[Document Insights & Patterns] + + P1 --> P2 --> P3 --> P4 + end + + Start --> Process + +Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state. + +REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy. \ No newline at end of file diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..a5df453 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,44 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone", + async headers() { + return [ + { + source: "/:path*", + headers: [ + { + key: "X-DNS-Prefetch-Control", + value: "on", + }, + { + key: "Strict-Transport-Security", + value: "max-age=63072000; includeSubDomains; preload", + }, + { + key: "X-Frame-Options", + value: "SAMEORIGIN", + }, + { + key: "X-Content-Type-Options", + value: "nosniff", + }, + { + key: "X-XSS-Protection", + value: "1; mode=block", + }, + { + key: "Referrer-Policy", + value: "strict-origin-when-cross-origin", + }, + { + key: "Permissions-Policy", + value: "camera=(), microphone=(), geolocation=()", + }, + ], + }, + ]; + }, +}; + +export default nextConfig; diff --git a/package.json b/package.json new file mode 100644 index 0000000..9020bd1 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "image-api", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint", + "db:generate": "drizzle-kit generate", + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.965.0", + "bcrypt": "^6.0.0", + "better-auth": "^1.4.10", + "dotenv": "^17.2.3", + "drizzle-orm": "^0.45.1", + "esbuild": "^0.25.12", + "jsonwebtoken": "^9.0.3", + "nanoid": "^5.1.6", + "next": "16.1.1", + "pg": "^8.16.3", + "postgres": "^3.4.7", + "react": "19.2.3", + "react-dom": "19.2.3", + "sharp": "^0.34.5", + "sweetalert2": "^11.26.17" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/bcrypt": "^6.0.0", + "@types/jsonwebtoken": "^9.0.10", + "@types/node": "^20", + "@types/pg": "^8.16.0", + "@types/react": "^19", + "@types/react-dom": "^19", + "drizzle-kit": "^0.31.8", + "eslint": "^9", + "eslint-config-next": "16.1.1", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/public/file.svg b/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/next.svg b/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/uploads/G2IZKMVncbgNhi9rU1bon.avif b/public/uploads/G2IZKMVncbgNhi9rU1bon.avif new file mode 100644 index 0000000..805751b Binary files /dev/null and b/public/uploads/G2IZKMVncbgNhi9rU1bon.avif differ diff --git a/public/uploads/UTwr4wJNmDaIHgmovLogH.avif b/public/uploads/UTwr4wJNmDaIHgmovLogH.avif new file mode 100644 index 0000000..c76fdac Binary files /dev/null and b/public/uploads/UTwr4wJNmDaIHgmovLogH.avif differ diff --git a/public/uploads/_u1OsfM__88agO_goDnRz.jpg b/public/uploads/_u1OsfM__88agO_goDnRz.jpg new file mode 100644 index 0000000..ea757cf Binary files /dev/null and b/public/uploads/_u1OsfM__88agO_goDnRz.jpg differ diff --git a/public/uploads/diQ-g_qzoYCI4GuOiNny6.avif b/public/uploads/diQ-g_qzoYCI4GuOiNny6.avif new file mode 100644 index 0000000..29b4c97 Binary files /dev/null and b/public/uploads/diQ-g_qzoYCI4GuOiNny6.avif differ diff --git a/public/uploads/kGGOVikvdoUO7F7ci0MLx.avif b/public/uploads/kGGOVikvdoUO7F7ci0MLx.avif new file mode 100644 index 0000000..c39ed43 Binary files /dev/null and b/public/uploads/kGGOVikvdoUO7F7ci0MLx.avif differ diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/window.svg b/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/r2-cors.json b/r2-cors.json new file mode 100644 index 0000000..f6fe61a --- /dev/null +++ b/r2-cors.json @@ -0,0 +1,9 @@ +[ + { + "AllowedOrigins": ["*"], + "AllowedMethods": ["GET", "HEAD"], + "AllowedHeaders": ["*"], + "ExposeHeaders": ["ETag"], + "MaxAgeSeconds": 3600 + } +] diff --git a/sadece login olmus userlerin giris yapab.txt b/sadece login olmus userlerin giris yapab.txt new file mode 100644 index 0000000..183464c --- /dev/null +++ b/sadece login olmus userlerin giris yapab.txt @@ -0,0 +1,3 @@ +sadece login olmus userlerin giris yapabilecegi bir sayfa olacak. ve sayfada resim dosyalri yuklenecek en boy kalite format vs kullnacini verdigi bilgilere gore +resim manipule edilecek ve database ye drizzle orm ile kaydedilecek. +resim url si çıkartilarak download edilebilir ve bir buton ile resmin url si kopyalanabilir. olacak ve bu url ile resim indirilebilir. \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3a13f90 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..c470aee --- /dev/null +++ b/yarn.lock @@ -0,0 +1,5008 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@aws-crypto/crc32@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" + integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/crc32c@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz#4e34aab7f419307821509a98b9b08e84e0c1917e" + integrity sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/sha1-browser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz#b0ee2d2821d3861f017e965ef3b4cb38e3b6a0f4" + integrity sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg== + dependencies: + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-browser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e" + integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== + dependencies: + "@aws-crypto/sha256-js" "^5.2.0" + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/supports-web-crypto@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz#a1e399af29269be08e695109aa15da0a07b5b5fb" + integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== + dependencies: + tslib "^2.6.2" + +"@aws-crypto/util@5.2.0", "@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-s3@^3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.965.0.tgz#4b64c49b9344727c82f936fce76e723aef2230ad" + integrity sha512-BTeaaU1iK0BfatTCrtYjNkIHCoZH256qOI18l9bK4z6mVOgpHkYN4RvOu+NnKgyX58n+HWfOuhtKUD4OE33Vdw== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.965.0" + "@aws-sdk/credential-provider-node" "3.965.0" + "@aws-sdk/middleware-bucket-endpoint" "3.965.0" + "@aws-sdk/middleware-expect-continue" "3.965.0" + "@aws-sdk/middleware-flexible-checksums" "3.965.0" + "@aws-sdk/middleware-host-header" "3.965.0" + "@aws-sdk/middleware-location-constraint" "3.965.0" + "@aws-sdk/middleware-logger" "3.965.0" + "@aws-sdk/middleware-recursion-detection" "3.965.0" + "@aws-sdk/middleware-sdk-s3" "3.965.0" + "@aws-sdk/middleware-ssec" "3.965.0" + "@aws-sdk/middleware-user-agent" "3.965.0" + "@aws-sdk/region-config-resolver" "3.965.0" + "@aws-sdk/signature-v4-multi-region" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-endpoints" "3.965.0" + "@aws-sdk/util-user-agent-browser" "3.965.0" + "@aws-sdk/util-user-agent-node" "3.965.0" + "@smithy/config-resolver" "^4.4.5" + "@smithy/core" "^3.20.0" + "@smithy/eventstream-serde-browser" "^4.2.7" + "@smithy/eventstream-serde-config-resolver" "^4.3.7" + "@smithy/eventstream-serde-node" "^4.2.7" + "@smithy/fetch-http-handler" "^5.3.8" + "@smithy/hash-blob-browser" "^4.2.8" + "@smithy/hash-node" "^4.2.7" + "@smithy/hash-stream-node" "^4.2.7" + "@smithy/invalid-dependency" "^4.2.7" + "@smithy/md5-js" "^4.2.7" + "@smithy/middleware-content-length" "^4.2.7" + "@smithy/middleware-endpoint" "^4.4.1" + "@smithy/middleware-retry" "^4.4.17" + "@smithy/middleware-serde" "^4.2.8" + "@smithy/middleware-stack" "^4.2.7" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/node-http-handler" "^4.4.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.16" + "@smithy/util-defaults-mode-node" "^4.2.19" + "@smithy/util-endpoints" "^3.2.7" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-retry" "^4.2.7" + "@smithy/util-stream" "^4.5.8" + "@smithy/util-utf8" "^4.2.0" + "@smithy/util-waiter" "^4.2.7" + tslib "^2.6.2" + +"@aws-sdk/client-sso@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.965.0.tgz#ff0727525041943a9aeda97ff778f3f368537eef" + integrity sha512-iv2tr+n4aZ+nPUFFvG00hISPuEd4DU+1/Q8rPAYKXsM+vEPJ2nAnP5duUOa2fbOLIUCRxX3dcQaQaghVHDHzQw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.965.0" + "@aws-sdk/middleware-host-header" "3.965.0" + "@aws-sdk/middleware-logger" "3.965.0" + "@aws-sdk/middleware-recursion-detection" "3.965.0" + "@aws-sdk/middleware-user-agent" "3.965.0" + "@aws-sdk/region-config-resolver" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-endpoints" "3.965.0" + "@aws-sdk/util-user-agent-browser" "3.965.0" + "@aws-sdk/util-user-agent-node" "3.965.0" + "@smithy/config-resolver" "^4.4.5" + "@smithy/core" "^3.20.0" + "@smithy/fetch-http-handler" "^5.3.8" + "@smithy/hash-node" "^4.2.7" + "@smithy/invalid-dependency" "^4.2.7" + "@smithy/middleware-content-length" "^4.2.7" + "@smithy/middleware-endpoint" "^4.4.1" + "@smithy/middleware-retry" "^4.4.17" + "@smithy/middleware-serde" "^4.2.8" + "@smithy/middleware-stack" "^4.2.7" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/node-http-handler" "^4.4.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.16" + "@smithy/util-defaults-mode-node" "^4.2.19" + "@smithy/util-endpoints" "^3.2.7" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-retry" "^4.2.7" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/core@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.965.0.tgz#b151ecc47a7861074b823079bb9217b09dce4769" + integrity sha512-aq9BhQxdHit8UUJ9C0im9TtuKeK0pT6NXmNJxMTCFeStI7GG7ImIsSislg3BZTIifVg1P6VLdzMyz9de85iutQ== + dependencies: + "@aws-sdk/types" "3.965.0" + "@aws-sdk/xml-builder" "3.965.0" + "@smithy/core" "^3.20.0" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/signature-v4" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/crc64-nvme@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/crc64-nvme/-/crc64-nvme-3.965.0.tgz#c51c032b73f5d6e532a849f34c5e7c9eea69b7e3" + integrity sha512-9FbIyJ/Zz1AdEIrb0+Pn7wRi+F/0Y566ooepg0hDyHUzRV3ZXKjOlu3wJH3YwTz2UkdwQmldfUos2yDJps7RyA== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-env@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.965.0.tgz#2312482be96381cd8c4271e7092b11d04a475da8" + integrity sha512-mdGnaIjMxTIjsb70dEj3VsWPWpoq1V5MWzBSfJq2H8zgMBXjn6d5/qHP8HMf53l9PrsgqzMpXGv3Av549A2x1g== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-http@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.965.0.tgz#fc1d682befbd53d84ee2dbf6e9b15f21e3cc4cf6" + integrity sha512-YuGQel9EgA/z25oeLM+GYYQS750+8AESvr7ZEmVnRPL0sg+K3DmGqdv+9gFjFd0UkLjTlC/jtbP2cuY6UcPiHQ== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/fetch-http-handler" "^5.3.8" + "@smithy/node-http-handler" "^4.4.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/util-stream" "^4.5.8" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-ini@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.965.0.tgz#9b55505877fb3b78ace662bf0b7094c70da60cc1" + integrity sha512-xRo72Prer5s0xYVSCxCymVIRSqrVlevK5cmU0GWq9yJtaBNpnx02jwdJg80t/Ni7pgbkQyFWRMcq38c1tc6M/w== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/credential-provider-env" "3.965.0" + "@aws-sdk/credential-provider-http" "3.965.0" + "@aws-sdk/credential-provider-login" "3.965.0" + "@aws-sdk/credential-provider-process" "3.965.0" + "@aws-sdk/credential-provider-sso" "3.965.0" + "@aws-sdk/credential-provider-web-identity" "3.965.0" + "@aws-sdk/nested-clients" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/credential-provider-imds" "^4.2.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-login@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.965.0.tgz#51d870135d53782093d7724ac554adbb3e5ea7ca" + integrity sha512-43/H8Qku8LHyugbhLo8kjD+eauhybCeVkmrnvWl8bXNHJP7xi1jCdtBQJKKJqiIHZws4MOEwkji8kFdAVRCe6g== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/nested-clients" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-node@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.965.0.tgz#147277bc7130cba720d565e729c449018e0c451f" + integrity sha512-cRxmMHF+Zh2lkkkEVduKl+8OQdtg/DhYA69+/7SPSQURlgyjFQGlRQ58B7q8abuNlrGT3sV+UzeOylZpJbV61Q== + dependencies: + "@aws-sdk/credential-provider-env" "3.965.0" + "@aws-sdk/credential-provider-http" "3.965.0" + "@aws-sdk/credential-provider-ini" "3.965.0" + "@aws-sdk/credential-provider-process" "3.965.0" + "@aws-sdk/credential-provider-sso" "3.965.0" + "@aws-sdk/credential-provider-web-identity" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/credential-provider-imds" "^4.2.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-process@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.965.0.tgz#3180204c906c1fcc0d3c154d313f271f9e1d5f0d" + integrity sha512-gmkPmdiR0yxnTzLPDb7rwrDhGuCUjtgnj8qWP+m0gSz/W43rR4jRPVEf6DUX2iC+ImQhxo3NFhuB3V42Kzo3TQ== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-sso@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.965.0.tgz#08b561b2690a5604b96d26e1d630d50e8c478fa8" + integrity sha512-N01AYvtCqG3Wo/s/LvYt19ity18/FqggiXT+elAs3X9Om/Wfx+hw9G+i7jaDmy+/xewmv8AdQ2SK5Q30dXw/Fw== + dependencies: + "@aws-sdk/client-sso" "3.965.0" + "@aws-sdk/core" "3.965.0" + "@aws-sdk/token-providers" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-web-identity@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.965.0.tgz#ccebeae664b3fd3d7f1e9b4b41ef1886f90d6258" + integrity sha512-T4gMZ2JzXnfxe1oTD+EDGLSxFfk1+WkLZdiHXEMZp8bFI1swP/3YyDFXI+Ib9Uq1JhnAmrCXtOnkicKEhDkdhQ== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/nested-clients" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-bucket-endpoint@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.965.0.tgz#4691dbc2e3d92629d3f03c0668a65ab59fb08b97" + integrity sha512-gbdv3Dl8l8xmg4oH60fXvfDyTxfx28w5/Hxdymx3vurM07tAyd4qld8zEXejnSpraTo45QcHRtk5auELIMfeag== + dependencies: + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-arn-parser" "3.965.0" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-config-provider" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-expect-continue@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.965.0.tgz#b5636e46c9c658c9ee0ed41b010b4c9c69b3ad6f" + integrity sha512-UBxVytsmhEmFwkBnt+aV0eAJ7uc+ouNokCqMBrQ7Oc5A77qhlcHfOgXIKz2SxqsiYTsDq+a0lWFM/XpyRWraqA== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-flexible-checksums@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.965.0.tgz#6c762eb02c152492979b4fb40ca8294cd3aaf2ad" + integrity sha512-5rzEW08trcpHMe6jkQyYc4PL1KG/H7BbnySFSzhih+r/gktQEiE36sb1BNf7av9I0Vk2Ccmt7wocB5PIT7GDkQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-crypto/util" "5.2.0" + "@aws-sdk/core" "3.965.0" + "@aws-sdk/crc64-nvme" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/is-array-buffer" "^4.2.0" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-stream" "^4.5.8" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-host-header@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz#3de254300a49633c65f767248b6a68571f869e96" + integrity sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-location-constraint@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.965.0.tgz#afda3f3f68725262c13e91a578a9d0186ae01e9f" + integrity sha512-07T1rwAarQs33mVg5U28AsSdLB5JUXu9yBTBmspFGajKVsEahIyntf53j9mAXF1N2KR0bNdP0J4A0kst4t43UQ== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-logger@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz#81eb6f075df979fa071347140dfba93cb87b5c9b" + integrity sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-recursion-detection@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz#82e92b7d1200e86e1a0643a0dca942bd63c9c355" + integrity sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA== + dependencies: + "@aws-sdk/types" "3.965.0" + "@aws/lambda-invoke-store" "^0.2.2" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-sdk-s3@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.965.0.tgz#6abae7dc82f7d6e776d033d208283f69184a6ee9" + integrity sha512-dXEgnojaaVRl+OlOx35mg3rYEbfffIN4X6tLmIfDnaKz0hMaDMvsE9jJXb/vBvokbdO1sVB27/2FEM4ttLSLnw== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-arn-parser" "3.965.0" + "@smithy/core" "^3.20.0" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/signature-v4" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/util-config-provider" "^4.2.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-stream" "^4.5.8" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-ssec@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.965.0.tgz#8e290e2297f19e451c1b4af69bb118ccdcc2a695" + integrity sha512-dke++CTw26y+a2D1DdVuZ4+2TkgItdx6TeuE0zOl4lsqXGvTBUG4eaIZalt7ZOAW5ys2pbDOk1bPuh4opoD3pQ== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-user-agent@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.965.0.tgz#d32760303030c4049d6aa3304af3e1b008275f07" + integrity sha512-RBEYVGgu/WeAt+H/qLrGc+t8LqAUkbyvh3wBfTiuAD+uBcWsKnvnB1iSBX75FearC0fmoxzXRUc0PMxMdqpjJQ== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-endpoints" "3.965.0" + "@smithy/core" "^3.20.0" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/nested-clients@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.965.0.tgz#0a760bd2bb40b12d4dc9d4c34e85c1ada1c5b77d" + integrity sha512-muNVUjUEU+/KLFrLzQ8PMXyw4+a/MP6t4GIvwLtyx/kH0rpSy5s0YmqacMXheuIe6F/5QT8uksXGNAQenitkGQ== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.965.0" + "@aws-sdk/middleware-host-header" "3.965.0" + "@aws-sdk/middleware-logger" "3.965.0" + "@aws-sdk/middleware-recursion-detection" "3.965.0" + "@aws-sdk/middleware-user-agent" "3.965.0" + "@aws-sdk/region-config-resolver" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@aws-sdk/util-endpoints" "3.965.0" + "@aws-sdk/util-user-agent-browser" "3.965.0" + "@aws-sdk/util-user-agent-node" "3.965.0" + "@smithy/config-resolver" "^4.4.5" + "@smithy/core" "^3.20.0" + "@smithy/fetch-http-handler" "^5.3.8" + "@smithy/hash-node" "^4.2.7" + "@smithy/invalid-dependency" "^4.2.7" + "@smithy/middleware-content-length" "^4.2.7" + "@smithy/middleware-endpoint" "^4.4.1" + "@smithy/middleware-retry" "^4.4.17" + "@smithy/middleware-serde" "^4.2.8" + "@smithy/middleware-stack" "^4.2.7" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/node-http-handler" "^4.4.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/smithy-client" "^4.10.2" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.16" + "@smithy/util-defaults-mode-node" "^4.2.19" + "@smithy/util-endpoints" "^3.2.7" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-retry" "^4.2.7" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/region-config-resolver@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz#1fc2a0abdd17ea5ab35828c15c6e1f0240961bbe" + integrity sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/config-resolver" "^4.4.5" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/signature-v4-multi-region@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.965.0.tgz#0a9d1f35bf895efe87660f72fb7c6454dac475d9" + integrity sha512-hgbAThbsUrWtNpFBQxzXevIfd5Qgr4TLbXY1AIbmpSX9fPVC114pdieRMpopJ0fYaJ7v5/blTiS6wzVdXleZ/w== + dependencies: + "@aws-sdk/middleware-sdk-s3" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/protocol-http" "^5.3.7" + "@smithy/signature-v4" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/token-providers@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.965.0.tgz#c759e73a38004a7a1011b7f38365ead433a726a7" + integrity sha512-aR0qxg0b8flkXJVE+CM1gzo7uJ57md50z2eyCwofC0QIz5Y0P7/7vvb9/dmUQt6eT9XRN5iRcUqq2IVxVDvJOw== + dependencies: + "@aws-sdk/core" "3.965.0" + "@aws-sdk/nested-clients" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/types@3.965.0", "@aws-sdk/types@^3.222.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.965.0.tgz#629f4d729cfc9c60047da912d450aa0b76e3afb9" + integrity sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-arn-parser@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.965.0.tgz#85d5fa58824bec65dd16b101caaba7101bb75909" + integrity sha512-bNGKr5Tct28jGLkL8xIkGu7swpDgBpkTVbGaofhzr/X80iclbOv656RGxhMpDvmc4S9UuQnqLRXyceNFNF2V7Q== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-endpoints@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz#f5b22ae9a2de6e7506f00079edf92cf764f278f6" + integrity sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + "@smithy/util-endpoints" "^3.2.7" + tslib "^2.6.2" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.965.0.tgz#0eae409c8479597ed6a19b44af72f0c9aa2a54c3" + integrity sha512-9LJFand4bIoOjOF4x3wx0UZYiFZRo4oUauxQSiEX2dVg+5qeBOJSjp2SeWykIE6+6frCZ5wvWm2fGLK8D32aJw== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-browser@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz#37f75ba21827566401f56274fb0f7be99a37c0da" + integrity sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ== + dependencies: + "@aws-sdk/types" "3.965.0" + "@smithy/types" "^4.11.0" + bowser "^2.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-node@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.965.0.tgz#67fa31e3de9a9f9f7aa449a235785eda0f82315a" + integrity sha512-kokIHUfNT3/P55E4fUJJrFHuuA9BbjFKUIxoLrd3UaRfdafT0ScRfg2eaZie6arf60EuhlUIZH0yALxttMEjxQ== + dependencies: + "@aws-sdk/middleware-user-agent" "3.965.0" + "@aws-sdk/types" "3.965.0" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@aws-sdk/xml-builder@3.965.0": + version "3.965.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz#f4aa21591c6d365e639e54b664cc39572732951e" + integrity sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g== + dependencies: + "@smithy/types" "^4.11.0" + fast-xml-parser "5.2.5" + tslib "^2.6.2" + +"@aws/lambda-invoke-store@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz#b00f7d6aedfe832ef6c84488f3a422cce6a47efa" + integrity sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg== + +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz" + integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== + +"@babel/core@^7.24.4": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz" + integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz" + integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== + dependencies: + "@babel/parser" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + +"@babel/parser@^7.24.4", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz" + integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== + dependencies: + "@babel/types" "^7.28.5" + +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz" + integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.5" + debug "^4.3.1" + +"@babel/types@^7.27.1", "@babel/types@^7.28.4", "@babel/types@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz" + integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@better-auth/core@1.4.10": + version "1.4.10" + resolved "https://registry.npmjs.org/@better-auth/core/-/core-1.4.10.tgz" + integrity sha512-AThrfb6CpG80wqkanfrbN2/fGOYzhGladHFf3JhaWt/3/Vtf4h084T6PJLrDE7M/vCCGYvDI1DkvP3P1OB2HAg== + dependencies: + "@standard-schema/spec" "^1.0.0" + zod "^4.1.12" + +"@better-auth/telemetry@1.4.10": + version "1.4.10" + resolved "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.4.10.tgz" + integrity sha512-Dq4XJX6EKsUu0h3jpRagX739p/VMOTcnJYWRrLtDYkqtZFg+sFiFsSWVcfapZoWpRSUGYX9iKwl6nDHn6Ju2oQ== + dependencies: + "@better-auth/utils" "0.3.0" + "@better-fetch/fetch" "1.1.21" + +"@better-auth/utils@0.3.0", "@better-auth/utils@^0.3.0": + version "0.3.0" + resolved "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz" + integrity sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw== + +"@better-fetch/fetch@1.1.21", "@better-fetch/fetch@^1.1.4": + version "1.1.21" + resolved "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz" + integrity sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A== + +"@drizzle-team/brocli@^0.10.2": + version "0.10.2" + resolved "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz" + integrity sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w== + +"@emnapi/core@^1.4.3", "@emnapi/core@^1.7.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" + integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.7.0", "@emnapi/runtime@^1.7.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0", "@emnapi/wasi-threads@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + +"@esbuild-kit/core-utils@^3.3.2": + version "3.3.2" + resolved "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz" + integrity sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ== + dependencies: + esbuild "~0.18.20" + source-map-support "^0.5.21" + +"@esbuild-kit/esm-loader@^2.5.5": + version "2.6.5" + resolved "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz" + integrity sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA== + dependencies: + "@esbuild-kit/core-utils" "^3.3.2" + get-tsconfig "^4.7.0" + +"@esbuild/aix-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" + integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" + integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" + integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/android-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" + integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" + integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/darwin-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" + integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" + integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/freebsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" + integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" + integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" + integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" + integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-loong64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" + integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-mips64el@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" + integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" + integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-riscv64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" + integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-s390x@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" + integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/linux-x64@0.25.12": + version "0.25.12" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz" + integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== + +"@esbuild/netbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" + integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/netbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" + integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== + +"@esbuild/openbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" + integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/openbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" + integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== + +"@esbuild/openharmony-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" + integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/sunos-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" + integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" + integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" + integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@esbuild/win32-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" + integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== + +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.21.1": + version "0.21.1" + resolved "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz" + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== + dependencies: + "@eslint/object-schema" "^2.1.7" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== + dependencies: + "@eslint/core" "^0.17.0" + +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.1": + version "3.3.3" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz" + integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.1" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.39.2": + version "9.39.2" + resolved "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz" + integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== + +"@eslint/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== + +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== + dependencies: + "@eslint/core" "^0.17.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.7" + resolved "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz" + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.4.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@img/colour@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz" + integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== + +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + +"@img/sharp-win32-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8" + integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw== + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.4", "@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@napi-rs/wasm-runtime@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz#c3705ab549d176b8dc5172723d6156c3dc426af2" + integrity sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A== + dependencies: + "@emnapi/core" "^1.7.1" + "@emnapi/runtime" "^1.7.1" + "@tybys/wasm-util" "^0.10.1" + +"@next/env@16.1.1": + version "16.1.1" + resolved "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz" + integrity sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA== + +"@next/eslint-plugin-next@16.1.1": + version "16.1.1" + resolved "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.1.tgz" + integrity sha512-Ovb/6TuLKbE1UiPcg0p39Ke3puyTCIKN9hGbNItmpQsp+WX3qrjO3WaMVSi6JHr9X1NrmthqIguVHodMJbh/dw== + dependencies: + fast-glob "3.3.1" + +"@next/swc-darwin-arm64@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz#1e7e87fd21fcabce546dfb04fb946ecd9f866917" + integrity sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA== + +"@next/swc-darwin-x64@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz#6617d03b96bdffad7bf4df50d4a699faea0d04c3" + integrity sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw== + +"@next/swc-linux-arm64-gnu@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz#d8337e2f4881a80221a1f56ac3f979b665b7e574" + integrity sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ== + +"@next/swc-linux-arm64-musl@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz#6c24392824406a50f27fb9cf4e49362d4666db1c" + integrity sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg== + +"@next/swc-linux-x64-gnu@16.1.1": + version "16.1.1" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz" + integrity sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ== + +"@next/swc-linux-x64-musl@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz#20c1ea0c98988c337614ce6fda01b82300ff00fd" + integrity sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA== + +"@next/swc-win32-arm64-msvc@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz#9d66be9dc4ebc458d445a7f6ee804f416d5c2daf" + integrity sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA== + +"@next/swc-win32-x64-msvc@16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz#96e9e335e2577481dab6fc7a2af48f3e4a28fbdb" + integrity sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw== + +"@noble/ciphers@^2.0.0": + version "2.1.1" + resolved "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.1.1.tgz" + integrity sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw== + +"@noble/hashes@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz" + integrity sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@smithy/abort-controller@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-4.2.7.tgz#b475e8d7bb1aeee45fdc8d984c35e6ca9bb0428c" + integrity sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader-native@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz#380266951d746b522b4ab2b16bfea6b451147b41" + integrity sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ== + dependencies: + "@smithy/util-base64" "^4.3.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz#776fec5eaa5ab5fa70d0d0174b7402420b24559c" + integrity sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA== + dependencies: + tslib "^2.6.2" + +"@smithy/config-resolver@^4.4.5": + version "4.4.5" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.4.5.tgz#35e792b6db00887bdd029df9b41780ca005d064b" + integrity sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg== + dependencies: + "@smithy/node-config-provider" "^4.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-config-provider" "^4.2.0" + "@smithy/util-endpoints" "^3.2.7" + "@smithy/util-middleware" "^4.2.7" + tslib "^2.6.2" + +"@smithy/core@^3.20.0", "@smithy/core@^3.20.1": + version "3.20.1" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.20.1.tgz#9a1e2dc77367b91d356ad26967074783467e6909" + integrity sha512-wOboSEdQ85dbKAJ0zL+wQ6b0HTSBRhtGa0PYKysQXkRg+vK0tdCRRVruiFM2QMprkOQwSYOnwF4og96PAaEGag== + dependencies: + "@smithy/middleware-serde" "^4.2.8" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-stream" "^4.5.8" + "@smithy/util-utf8" "^4.2.0" + "@smithy/uuid" "^1.1.0" + tslib "^2.6.2" + +"@smithy/credential-provider-imds@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.7.tgz#bfbbf797599c3944509ef4c9690a5c960e153ef5" + integrity sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA== + dependencies: + "@smithy/node-config-provider" "^4.3.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-4.2.7.tgz#8f8bba50fb1871d98e0cda28b0842ade6ee72021" + integrity sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^4.11.0" + "@smithy/util-hex-encoding" "^4.2.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-browser@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.7.tgz#9270fff07c53c51b2d1cff9ce6227f2a01f8424d" + integrity sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^4.3.7": + version "4.3.7" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.7.tgz#a57b74a230767171a232eca4bbf6283c3107bb9c" + integrity sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-node@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.7.tgz#4b0a306ef81bf1854c437322443e22f69845e7c7" + integrity sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-universal@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.7.tgz#11ec67a86c8297d153ce3bc9505715ed80058c34" + integrity sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g== + dependencies: + "@smithy/eventstream-codec" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/fetch-http-handler@^5.3.8": + version "5.3.8" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.8.tgz#092a1b6dfdf5981853c7b0d98ebf048cc5e56c2b" + integrity sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg== + dependencies: + "@smithy/protocol-http" "^5.3.7" + "@smithy/querystring-builder" "^4.2.7" + "@smithy/types" "^4.11.0" + "@smithy/util-base64" "^4.3.0" + tslib "^2.6.2" + +"@smithy/hash-blob-browser@^4.2.8": + version "4.2.8" + resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.8.tgz#9748338e2d0e0bceecbee64739d71591c61924ff" + integrity sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw== + dependencies: + "@smithy/chunked-blob-reader" "^5.2.0" + "@smithy/chunked-blob-reader-native" "^4.2.1" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/hash-node@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-4.2.7.tgz#74a3d3ed8d47ecbe68d19e79af1d23f5abbb7253" + integrity sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw== + dependencies: + "@smithy/types" "^4.11.0" + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/hash-stream-node@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-4.2.7.tgz#4a0122edd3ea6a63866823d476af5afd1bd541e2" + integrity sha512-ZQVoAwNYnFMIbd4DUc517HuwNelJUY6YOzwqrbcAgCnVn+79/OK7UjwA93SPpdTOpKDVkLIzavWm/Ck7SmnDPQ== + dependencies: + "@smithy/types" "^4.11.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/invalid-dependency@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-4.2.7.tgz#0afcc586db3032f94f3c1ea1054665b16f793b16" + integrity sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/is-array-buffer@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111" + integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== + dependencies: + tslib "^2.6.2" + +"@smithy/is-array-buffer@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz#b0f874c43887d3ad44f472a0f3f961bcce0550c2" + integrity sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ== + dependencies: + tslib "^2.6.2" + +"@smithy/md5-js@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-4.2.7.tgz#6d13a753a505532fbf78a083adc1bef532bb7e34" + integrity sha512-Wv6JcUxtOLTnxvNjDnAiATUsk8gvA6EeS8zzHig07dotpByYsLot+m0AaQEniUBjx97AC41MQR4hW0baraD1Xw== + dependencies: + "@smithy/types" "^4.11.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/middleware-content-length@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-4.2.7.tgz#d9968dc1a6ac3aea9f05a92a900f231e72ba3fbc" + integrity sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg== + dependencies: + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/middleware-endpoint@^4.4.1", "@smithy/middleware-endpoint@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.2.tgz#4b33728b015e6f1e38b5d0e87ea2b46e017f7a17" + integrity sha512-mqpAdux0BNmZu/SqkFhQEnod4fX23xxTvU2LUpmKp0JpSI+kPYCiHJMmzREr8yxbNxKL2/DU1UZm9i++ayU+2g== + dependencies: + "@smithy/core" "^3.20.1" + "@smithy/middleware-serde" "^4.2.8" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + "@smithy/url-parser" "^4.2.7" + "@smithy/util-middleware" "^4.2.7" + tslib "^2.6.2" + +"@smithy/middleware-retry@^4.4.17": + version "4.4.18" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.4.18.tgz#26604c9ff6927f3d3070f1c7e81e9245cf0248ca" + integrity sha512-E5hulijA59nBk/zvcwVMaS7FG7Y4l6hWA9vrW018r+8kiZef4/ETQaPI4oY+3zsy9f6KqDv3c4VKtO4DwwgpCg== + dependencies: + "@smithy/node-config-provider" "^4.3.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/service-error-classification" "^4.2.7" + "@smithy/smithy-client" "^4.10.3" + "@smithy/types" "^4.11.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-retry" "^4.2.7" + "@smithy/uuid" "^1.1.0" + tslib "^2.6.2" + +"@smithy/middleware-serde@^4.2.8": + version "4.2.8" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.2.8.tgz#57f1baa98899fd96f4737465b3a363acf1963e0a" + integrity sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w== + dependencies: + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/middleware-stack@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-4.2.7.tgz#39d7bdf3a403b3d1f82caad71be66bfe7d88a790" + integrity sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/node-config-provider@^4.3.7": + version "4.3.7" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz#c023fa857b008c314f621fb5b124724c157b2fd3" + integrity sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw== + dependencies: + "@smithy/property-provider" "^4.2.7" + "@smithy/shared-ini-file-loader" "^4.4.2" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/node-http-handler@^4.4.7": + version "4.4.7" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.4.7.tgz#ebdb6c10e8d203af22429987ed795b105e4e848f" + integrity sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ== + dependencies: + "@smithy/abort-controller" "^4.2.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/querystring-builder" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/property-provider@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-4.2.7.tgz#cd0044e13495cf4064b3a6ed3299e5f549ba7513" + integrity sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/protocol-http@^5.3.7": + version "5.3.7" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-5.3.7.tgz#2a58a1dfdb7cc90a8c79f081b5b6cf96d888891a" + integrity sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/querystring-builder@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-4.2.7.tgz#92ada986c6026a56b26e36c64bcea6ece68d0ecb" + integrity sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg== + dependencies: + "@smithy/types" "^4.11.0" + "@smithy/util-uri-escape" "^4.2.0" + tslib "^2.6.2" + +"@smithy/querystring-parser@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-4.2.7.tgz#4c645b8164d7c17270b60fc2e0f5098ae3bf0fad" + integrity sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/service-error-classification@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.2.7.tgz#bcad2f16874187135d24ab588a3bb4424b073d89" + integrity sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA== + dependencies: + "@smithy/types" "^4.11.0" + +"@smithy/shared-ini-file-loader@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz#8fa1b459de485b11185fe8c64182e3205a280ba9" + integrity sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/signature-v4@^5.3.7": + version "5.3.7" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.3.7.tgz#20fe4e8e9abea413b1bdbf8560e74ad7cdee65cf" + integrity sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg== + dependencies: + "@smithy/is-array-buffer" "^4.2.0" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-hex-encoding" "^4.2.0" + "@smithy/util-middleware" "^4.2.7" + "@smithy/util-uri-escape" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/smithy-client@^4.10.2", "@smithy/smithy-client@^4.10.3": + version "4.10.3" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.10.3.tgz#d49ce7597d90daf062295b3607d06be86c428708" + integrity sha512-EfECiO/0fAfb590LBnUe7rI5ux7XfquQ8LBzTe7gxw0j9QW/q8UT/EHWHlxV/+jhQ3+Ssga9uUYXCQgImGMbNg== + dependencies: + "@smithy/core" "^3.20.1" + "@smithy/middleware-endpoint" "^4.4.2" + "@smithy/middleware-stack" "^4.2.7" + "@smithy/protocol-http" "^5.3.7" + "@smithy/types" "^4.11.0" + "@smithy/util-stream" "^4.5.8" + tslib "^2.6.2" + +"@smithy/types@^4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.11.0.tgz#c02f6184dcb47c4f0b387a32a7eca47956cc09f1" + integrity sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA== + dependencies: + tslib "^2.6.2" + +"@smithy/url-parser@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-4.2.7.tgz#3137e6f190c446dc8d89271c35f46a2e704bca19" + integrity sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg== + dependencies: + "@smithy/querystring-parser" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-base64@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-4.3.0.tgz#5e287b528793aa7363877c1a02cd880d2e76241d" + integrity sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ== + dependencies: + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-body-length-browser@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz#04e9fc51ee7a3e7f648a4b4bcdf96c350cfa4d61" + integrity sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-body-length-node@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz#79c8a5d18e010cce6c42d5cbaf6c1958523e6fec" + integrity sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-buffer-from@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b" + integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== + dependencies: + "@smithy/is-array-buffer" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-buffer-from@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz#7abd12c4991b546e7cee24d1e8b4bfaa35c68a9d" + integrity sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew== + dependencies: + "@smithy/is-array-buffer" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-config-provider@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz#2e4722937f8feda4dcb09672c59925a4e6286cfc" + integrity sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q== + dependencies: + tslib "^2.6.2" + +"@smithy/util-defaults-mode-browser@^4.3.16": + version "4.3.17" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.17.tgz#9de8fa0de4922f0b84b0326658db2f83e0dc38d5" + integrity sha512-dwN4GmivYF1QphnP3xJESXKtHvkkvKHSZI8GrSKMVoENVSKW2cFPRYC4ZgstYjUHdR3zwaDkIaTDIp26JuY7Cw== + dependencies: + "@smithy/property-provider" "^4.2.7" + "@smithy/smithy-client" "^4.10.3" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-defaults-mode-node@^4.2.19": + version "4.2.20" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.20.tgz#ebd322fe527c60298d0e0fcf5253e7a61446af81" + integrity sha512-VD/I4AEhF1lpB3B//pmOIMBNLMrtdMXwy9yCOfa2QkJGDr63vH3RqPbSAKzoGMov3iryCxTXCxSsyGmEB8PDpg== + dependencies: + "@smithy/config-resolver" "^4.4.5" + "@smithy/credential-provider-imds" "^4.2.7" + "@smithy/node-config-provider" "^4.3.7" + "@smithy/property-provider" "^4.2.7" + "@smithy/smithy-client" "^4.10.3" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-endpoints@^3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz#78cd5dd4aac8d9977f49d256d1e3418a09cade72" + integrity sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg== + dependencies: + "@smithy/node-config-provider" "^4.3.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-hex-encoding@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz#1c22ea3d1e2c3a81ff81c0a4f9c056a175068a7b" + integrity sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw== + dependencies: + tslib "^2.6.2" + +"@smithy/util-middleware@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-4.2.7.tgz#1cae2c4fd0389ac858d29f7170c33b4443e83524" + integrity sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w== + dependencies: + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-retry@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.2.7.tgz#4abb0d85fbd766757d4569227a68d7caa3a7b8bb" + integrity sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg== + dependencies: + "@smithy/service-error-classification" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/util-stream@^4.5.8": + version "4.5.8" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.5.8.tgz#f3c79ff0720ebbae5b90e15be5482b4eeb297882" + integrity sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w== + dependencies: + "@smithy/fetch-http-handler" "^5.3.8" + "@smithy/node-http-handler" "^4.4.7" + "@smithy/types" "^4.11.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-hex-encoding" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-uri-escape@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz#096a4cec537d108ac24a68a9c60bee73fc7e3a9e" + integrity sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-utf8@^2.0.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5" + integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== + dependencies: + "@smithy/util-buffer-from" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-utf8@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-4.2.0.tgz#8b19d1514f621c44a3a68151f3d43e51087fed9d" + integrity sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw== + dependencies: + "@smithy/util-buffer-from" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-waiter@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.2.7.tgz#1865defa25e4812c3e338447587332fb316421d8" + integrity sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw== + dependencies: + "@smithy/abort-controller" "^4.2.7" + "@smithy/types" "^4.11.0" + tslib "^2.6.2" + +"@smithy/uuid@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@smithy/uuid/-/uuid-1.1.0.tgz#9fd09d3f91375eab94f478858123387df1cda987" + integrity sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw== + dependencies: + tslib "^2.6.2" + +"@standard-schema/spec@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz" + integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== + +"@swc/helpers@0.5.15": + version "0.5.15" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz" + integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g== + dependencies: + tslib "^2.8.0" + +"@tailwindcss/node@4.1.18": + version "4.1.18" + resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz" + integrity sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ== + dependencies: + "@jridgewell/remapping" "^2.3.4" + enhanced-resolve "^5.18.3" + jiti "^2.6.1" + lightningcss "1.30.2" + magic-string "^0.30.21" + source-map-js "^1.2.1" + tailwindcss "4.1.18" + +"@tailwindcss/oxide-android-arm64@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz#79717f87e90135e5d3d23a3d3aecde4ca5595dd5" + integrity sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q== + +"@tailwindcss/oxide-darwin-arm64@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz#7fa47608d62d60e9eb020682249d20159667fbb0" + integrity sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A== + +"@tailwindcss/oxide-darwin-x64@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz#c05991c85aa2af47bf9d1f8172fe9e4636591e79" + integrity sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw== + +"@tailwindcss/oxide-freebsd-x64@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz#3d48e8d79fd08ece0e02af8e72d5059646be34d0" + integrity sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz#982ecd1a65180807ccfde67dc17c6897f2e50aa8" + integrity sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz#df49357bc9737b2e9810ea950c1c0647ba6573c3" + integrity sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz#b266c12822bf87883cf152615f8fffb8519d689c" + integrity sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.18": + version "4.1.18" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz" + integrity sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g== + +"@tailwindcss/oxide-linux-x64-musl@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz#3380e17f7be391f1ef924be9f0afe1f304fe3478" + integrity sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ== + +"@tailwindcss/oxide-wasm32-wasi@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz#9464df0e28a499aab1c55e97682be37b3a656c88" + integrity sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA== + dependencies: + "@emnapi/core" "^1.7.1" + "@emnapi/runtime" "^1.7.1" + "@emnapi/wasi-threads" "^1.1.0" + "@napi-rs/wasm-runtime" "^1.1.0" + "@tybys/wasm-util" "^0.10.1" + tslib "^2.4.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz#bbcdd59c628811f6a0a4d5b09616967d8fb0c4d4" + integrity sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.18": + version "4.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz#9c628d04623aa4c3536c508289f58d58ba4b3fb1" + integrity sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q== + +"@tailwindcss/oxide@4.1.18": + version "4.1.18" + resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz" + integrity sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A== + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.18" + "@tailwindcss/oxide-darwin-arm64" "4.1.18" + "@tailwindcss/oxide-darwin-x64" "4.1.18" + "@tailwindcss/oxide-freebsd-x64" "4.1.18" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.18" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.18" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.18" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.18" + "@tailwindcss/oxide-linux-x64-musl" "4.1.18" + "@tailwindcss/oxide-wasm32-wasi" "4.1.18" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.18" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.18" + +"@tailwindcss/postcss@^4": + version "4.1.18" + resolved "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz" + integrity sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g== + dependencies: + "@alloc/quick-lru" "^5.2.0" + "@tailwindcss/node" "4.1.18" + "@tailwindcss/oxide" "4.1.18" + postcss "^8.4.41" + tailwindcss "4.1.18" + +"@tybys/wasm-util@^0.10.0", "@tybys/wasm-util@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/bcrypt@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz" + integrity sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ== + dependencies: + "@types/node" "*" + +"@types/estree@^1.0.6": + version "1.0.8" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/jsonwebtoken@^9.0.10": + version "9.0.10" + resolved "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz" + integrity sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA== + dependencies: + "@types/ms" "*" + "@types/node" "*" + +"@types/ms@*": + version "2.1.0" + resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz" + integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== + +"@types/node@*", "@types/node@^20": + version "20.19.27" + resolved "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz" + integrity sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug== + dependencies: + undici-types "~6.21.0" + +"@types/pg@^8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz" + integrity sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^2.2.0" + +"@types/react-dom@^19": + version "19.2.3" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz" + integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== + +"@types/react@^19": + version "19.2.7" + resolved "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz" + integrity sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg== + dependencies: + csstype "^3.2.2" + +"@typescript-eslint/eslint-plugin@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz" + integrity sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/type-utils" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.4.0" + +"@typescript-eslint/parser@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.52.0.tgz" + integrity sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg== + dependencies: + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.52.0.tgz" + integrity sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.52.0" + "@typescript-eslint/types" "^8.52.0" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.52.0.tgz" + integrity sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA== + dependencies: + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + +"@typescript-eslint/tsconfig-utils@8.52.0", "@typescript-eslint/tsconfig-utils@^8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.52.0.tgz" + integrity sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg== + +"@typescript-eslint/type-utils@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.52.0.tgz" + integrity sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ== + dependencies: + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + debug "^4.4.3" + ts-api-utils "^2.4.0" + +"@typescript-eslint/types@8.52.0", "@typescript-eslint/types@^8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.52.0.tgz" + integrity sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg== + +"@typescript-eslint/typescript-estree@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.52.0.tgz" + integrity sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ== + dependencies: + "@typescript-eslint/project-service" "8.52.0" + "@typescript-eslint/tsconfig-utils" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + debug "^4.4.3" + minimatch "^9.0.5" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.4.0" + +"@typescript-eslint/utils@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.52.0.tgz" + integrity sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + +"@typescript-eslint/visitor-keys@8.52.0": + version "8.52.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.52.0.tgz" + integrity sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ== + dependencies: + "@typescript-eslint/types" "8.52.0" + eslint-visitor-keys "^4.2.1" + +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + +array-includes@^3.1.6, array-includes@^3.1.8, array-includes@^3.1.9: + version "3.1.9" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.0" + es-object-atoms "^1.1.1" + get-intrinsic "^1.3.0" + is-string "^1.1.1" + math-intrinsics "^1.1.0" + +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.6: + version "1.2.6" + resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.2, array.prototype.flatmap@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axe-core@^4.10.0: + version "4.11.0" + resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz" + integrity sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ== + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +baseline-browser-mapping@^2.8.3, baseline-browser-mapping@^2.9.0: + version "2.9.11" + resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz" + integrity sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ== + +bcrypt@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz" + integrity sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg== + dependencies: + node-addon-api "^8.3.0" + node-gyp-build "^4.8.4" + +better-auth@^1.4.10: + version "1.4.10" + resolved "https://registry.npmjs.org/better-auth/-/better-auth-1.4.10.tgz" + integrity sha512-0kqwEBJLe8eyFzbUspRG/htOriCf9uMLlnpe34dlIJGdmDfPuQISd4shShvUrvIVhPxsY1dSTXdXPLpqISYOYg== + dependencies: + "@better-auth/core" "1.4.10" + "@better-auth/telemetry" "1.4.10" + "@better-auth/utils" "0.3.0" + "@better-fetch/fetch" "1.1.21" + "@noble/ciphers" "^2.0.0" + "@noble/hashes" "^2.0.0" + better-call "1.1.7" + defu "^6.1.4" + jose "^6.1.0" + kysely "^0.28.5" + nanostores "^1.0.1" + zod "^4.1.12" + +better-call@1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/better-call/-/better-call-1.1.7.tgz" + integrity sha512-6gaJe1bBIEgVebQu/7q9saahVzvBsGaByEnE8aDVncZEDiJO7sdNB28ot9I6iXSbR25egGmmZ6aIURXyQHRraQ== + dependencies: + "@better-auth/utils" "^0.3.0" + "@better-fetch/fetch" "^1.1.4" + rou3 "^0.7.10" + set-cookie-parser "^2.7.1" + +bowser@^2.11.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.13.1.tgz#5a4c652de1d002f847dd011819f5fc729f308a7e" + integrity sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +buffer-equal-constant-time@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001759: + version "1.0.30001762" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz" + integrity sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +defu@^6.1.4: + version "6.1.4" + resolved "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + +detect-libc@^2.0.3, detect-libc@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +dotenv@^17.2.3: + version "17.2.3" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz" + integrity sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w== + +drizzle-kit@^0.31.8: + version "0.31.8" + resolved "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.8.tgz" + integrity sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg== + dependencies: + "@drizzle-team/brocli" "^0.10.2" + "@esbuild-kit/esm-loader" "^2.5.5" + esbuild "^0.25.4" + esbuild-register "^3.5.0" + +drizzle-orm@^0.45.1: + version "0.45.1" + resolved "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.1.tgz" + integrity sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA== + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enhanced-resolve@^5.18.3: + version "5.18.4" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz" + integrity sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1: + version "1.24.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz" + integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-iterator-helpers@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz" + integrity sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.1" + es-errors "^1.3.0" + es-set-tostringtag "^2.1.0" + function-bind "^1.1.2" + get-intrinsic "^1.3.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.5" + safe-array-concat "^1.1.3" + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== + dependencies: + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + +esbuild-register@^3.5.0: + version "3.6.0" + resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz" + integrity sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg== + dependencies: + debug "^4.3.4" + +esbuild@^0.25.12, esbuild@^0.25.4: + version "0.25.12" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz" + integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.12" + "@esbuild/android-arm" "0.25.12" + "@esbuild/android-arm64" "0.25.12" + "@esbuild/android-x64" "0.25.12" + "@esbuild/darwin-arm64" "0.25.12" + "@esbuild/darwin-x64" "0.25.12" + "@esbuild/freebsd-arm64" "0.25.12" + "@esbuild/freebsd-x64" "0.25.12" + "@esbuild/linux-arm" "0.25.12" + "@esbuild/linux-arm64" "0.25.12" + "@esbuild/linux-ia32" "0.25.12" + "@esbuild/linux-loong64" "0.25.12" + "@esbuild/linux-mips64el" "0.25.12" + "@esbuild/linux-ppc64" "0.25.12" + "@esbuild/linux-riscv64" "0.25.12" + "@esbuild/linux-s390x" "0.25.12" + "@esbuild/linux-x64" "0.25.12" + "@esbuild/netbsd-arm64" "0.25.12" + "@esbuild/netbsd-x64" "0.25.12" + "@esbuild/openbsd-arm64" "0.25.12" + "@esbuild/openbsd-x64" "0.25.12" + "@esbuild/openharmony-arm64" "0.25.12" + "@esbuild/sunos-x64" "0.25.12" + "@esbuild/win32-arm64" "0.25.12" + "@esbuild/win32-ia32" "0.25.12" + "@esbuild/win32-x64" "0.25.12" + +esbuild@~0.18.20: + version "0.18.20" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-next@16.1.1: + version "16.1.1" + resolved "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.1.tgz" + integrity sha512-55nTpVWm3qeuxoQKLOjQVciKZJUphKrNM0fCcQHAIOGl6VFXgaqeMfv0aKJhs7QtcnlAPhNVqsqRfRjeKBPIUA== + dependencies: + "@next/eslint-plugin-next" "16.1.1" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.32.0" + eslint-plugin-jsx-a11y "^6.10.0" + eslint-plugin-react "^7.37.0" + eslint-plugin-react-hooks "^7.0.0" + globals "16.4.0" + typescript-eslint "^8.46.0" + +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.5.2: + version "3.10.1" + resolved "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz" + integrity sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.4.0" + get-tsconfig "^4.10.0" + is-bun-module "^2.0.0" + stable-hash "^0.0.5" + tinyglobby "^0.2.13" + unrs-resolver "^1.6.2" + +eslint-module-utils@^2.12.1: + version "2.12.1" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz" + integrity sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.32.0: + version "2.32.0" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz" + integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.9" + array.prototype.findlastindex "^1.2.6" + array.prototype.flat "^1.3.3" + array.prototype.flatmap "^1.3.3" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.1" + hasown "^2.0.2" + is-core-module "^2.16.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.1" + semver "^6.3.1" + string.prototype.trimend "^1.0.9" + tsconfig-paths "^3.15.0" + +eslint-plugin-jsx-a11y@^6.10.0: + version "6.10.2" + resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz" + integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q== + dependencies: + aria-query "^5.3.2" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.1" + +eslint-plugin-react-hooks@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz" + integrity sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA== + dependencies: + "@babel/core" "^7.24.4" + "@babel/parser" "^7.24.4" + hermes-parser "^0.25.1" + zod "^3.25.0 || ^4.0.0" + zod-validation-error "^3.5.0 || ^4.0.0" + +eslint-plugin-react@^7.37.0: + version "7.37.5" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.3" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.2.1" + estraverse "^5.3.0" + hasown "^2.0.2" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.9" + object.fromentries "^2.0.8" + object.values "^1.2.1" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.12" + string.prototype.repeat "^1.0.0" + +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9: + version "9.39.2" + resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz" + integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.1" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.39.2" + "@eslint/plugin-kit" "^0.4.1" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + +esquery@^1.5.0: + version "1.7.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-xml-parser@5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz#4809fdfb1310494e341098c25cb1341a01a9144a" + integrity sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ== + dependencies: + strnum "^2.1.0" + +fastq@^1.6.0: + version "1.20.1" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz" + integrity sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw== + dependencies: + reusify "^1.0.4" + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +generator-function@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz" + integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + +get-tsconfig@^4.10.0, get-tsconfig@^4.7.0: + version "4.13.0" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz" + integrity sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@16.4.0: + version "16.4.0" + resolved "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz" + integrity sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw== + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== + +hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== + dependencies: + hermes-estree "0.25.1" + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-bun-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz" + integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== + dependencies: + semver "^7.7.1" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + +is-generator-function@^1.0.10: + version "1.1.2" + resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +iterator.prototype@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz" + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== + dependencies: + define-data-property "^1.1.4" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + get-proto "^1.0.0" + has-symbols "^1.1.0" + set-function-name "^2.0.2" + +jiti@^2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz" + integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ== + +jose@^6.1.0: + version "6.1.3" + resolved "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz" + integrity sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonwebtoken@^9.0.3: + version "9.0.3" + resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz" + integrity sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g== + dependencies: + jws "^4.0.1" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +jwa@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz" + integrity sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg== + dependencies: + buffer-equal-constant-time "^1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz" + integrity sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA== + dependencies: + jwa "^2.0.1" + safe-buffer "^5.0.1" + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kysely@^0.28.5: + version "0.28.9" + resolved "https://registry.npmjs.org/kysely/-/kysely-0.28.9.tgz" + integrity sha512-3BeXMoiOhpOwu62CiVpO6lxfq4eS6KMYfQdMsN/2kUCRNuF2YiEr7u0HLHaQU+O4Xu8YXE3bHVkwaQ85i72EuA== + +language-subtag-registry@^0.3.20: + version "0.3.23" + resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lightningcss-android-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz#6966b7024d39c94994008b548b71ab360eb3a307" + integrity sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A== + +lightningcss-darwin-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz#a5fa946d27c029e48c7ff929e6e724a7de46eb2c" + integrity sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA== + +lightningcss-darwin-x64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz#5ce87e9cd7c4f2dcc1b713f5e8ee185c88d9b7cd" + integrity sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ== + +lightningcss-freebsd-x64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz#6ae1d5e773c97961df5cff57b851807ef33692a5" + integrity sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA== + +lightningcss-linux-arm-gnueabihf@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz#62c489610c0424151a6121fa99d77731536cdaeb" + integrity sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA== + +lightningcss-linux-arm64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz#2a3661b56fe95a0cafae90be026fe0590d089298" + integrity sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A== + +lightningcss-linux-arm64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz#d7ddd6b26959245e026bc1ad9eb6aa983aa90e6b" + integrity sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA== + +lightningcss-linux-x64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz" + integrity sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w== + +lightningcss-linux-x64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz#808c2e91ce0bf5d0af0e867c6152e5378c049728" + integrity sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA== + +lightningcss-win32-arm64-msvc@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz#ab4a8a8a2e6a82a4531e8bbb6bf0ff161ee6625a" + integrity sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ== + +lightningcss-win32-x64-msvc@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz#f01f382c8e0a27e1c018b0bee316d210eac43b6e" + integrity sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw== + +lightningcss@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz" + integrity sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-android-arm64 "1.30.2" + lightningcss-darwin-arm64 "1.30.2" + lightningcss-darwin-x64 "1.30.2" + lightningcss-freebsd-x64 "1.30.2" + lightningcss-linux-arm-gnueabihf "1.30.2" + lightningcss-linux-arm64-gnu "1.30.2" + lightningcss-linux-arm64-musl "1.30.2" + lightningcss-linux-x64-gnu "1.30.2" + lightningcss-linux-x64-musl "1.30.2" + lightningcss-win32-arm64-msvc "1.30.2" + lightningcss-win32-x64-msvc "1.30.2" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.30.21: + version "0.30.21" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.11, nanoid@^3.3.6: + version "3.3.11" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +nanoid@^5.1.6: + version "5.1.6" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz" + integrity sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg== + +nanostores@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/nanostores/-/nanostores-1.1.0.tgz" + integrity sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA== + +napi-postinstall@^0.3.0: + version "0.3.4" + resolved "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz" + integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next@16.1.1: + version "16.1.1" + resolved "https://registry.npmjs.org/next/-/next-16.1.1.tgz" + integrity sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w== + dependencies: + "@next/env" "16.1.1" + "@swc/helpers" "0.5.15" + baseline-browser-mapping "^2.8.3" + caniuse-lite "^1.0.30001579" + postcss "8.4.31" + styled-jsx "5.1.6" + optionalDependencies: + "@next/swc-darwin-arm64" "16.1.1" + "@next/swc-darwin-x64" "16.1.1" + "@next/swc-linux-arm64-gnu" "16.1.1" + "@next/swc-linux-arm64-musl" "16.1.1" + "@next/swc-linux-x64-gnu" "16.1.1" + "@next/swc-linux-x64-musl" "16.1.1" + "@next/swc-win32-arm64-msvc" "16.1.1" + "@next/swc-win32-x64-msvc" "16.1.1" + sharp "^0.34.4" + +node-addon-api@^8.3.0: + version "8.5.0" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz" + integrity sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A== + +node-gyp-build@^4.8.4: + version "4.8.4" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-object-atoms "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.1.6, object.values@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pg-cloudflare@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz" + integrity sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg== + +pg-connection-string@^2.9.1: + version "2.9.1" + resolved "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz" + integrity sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.10.1: + version "3.10.1" + resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz" + integrity sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg== + +pg-protocol@*, pg-protocol@^1.10.3: + version "1.10.3" + resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz" + integrity sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ== + +pg-types@2.2.0, pg-types@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.16.3: + version "8.16.3" + resolved "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz" + integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw== + dependencies: + pg-connection-string "^2.9.1" + pg-pool "^3.10.1" + pg-protocol "^1.10.3" + pg-types "2.2.0" + pgpass "1.0.5" + optionalDependencies: + pg-cloudflare "^1.2.7" + +pgpass@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.41: + version "8.5.6" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz" + integrity sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +postgres@^3.4.7: + version "3.4.7" + resolved "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz" + integrity sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-dom@19.2.3: + version "19.2.3" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz" + integrity sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg== + dependencies: + scheduler "^0.27.0" + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react@19.2.3: + version "19.2.3" + resolved "https://registry.npmjs.org/react/-/react-19.2.3.tgz" + integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA== + +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.22.4: + version "1.22.11" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rou3@^0.7.10: + version "0.7.12" + resolved "https://registry.npmjs.org/rou3/-/rou3-0.7.12.tgz" + integrity sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +scheduler@^0.27.0: + 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== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.7.1, semver@^7.7.3: + version "7.7.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +set-cookie-parser@^2.7.1: + version "2.7.2" + resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz" + integrity sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw== + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + +sharp@^0.34.4, sharp@^0.34.5: + version "0.34.5" + resolved "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz" + integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.2" + semver "^7.7.3" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.5" + "@img/sharp-darwin-x64" "0.34.5" + "@img/sharp-libvips-darwin-arm64" "1.2.4" + "@img/sharp-libvips-darwin-x64" "1.2.4" + "@img/sharp-libvips-linux-arm" "1.2.4" + "@img/sharp-libvips-linux-arm64" "1.2.4" + "@img/sharp-libvips-linux-ppc64" "1.2.4" + "@img/sharp-libvips-linux-riscv64" "1.2.4" + "@img/sharp-libvips-linux-s390x" "1.2.4" + "@img/sharp-libvips-linux-x64" "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + "@img/sharp-linux-arm" "0.34.5" + "@img/sharp-linux-arm64" "0.34.5" + "@img/sharp-linux-ppc64" "0.34.5" + "@img/sharp-linux-riscv64" "0.34.5" + "@img/sharp-linux-s390x" "0.34.5" + "@img/sharp-linux-x64" "0.34.5" + "@img/sharp-linuxmusl-arm64" "0.34.5" + "@img/sharp-linuxmusl-x64" "0.34.5" + "@img/sharp-wasm32" "0.34.5" + "@img/sharp-win32-arm64" "0.34.5" + "@img/sharp-win32-ia32" "0.34.5" + "@img/sharp-win32-x64" "0.34.5" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map-support@^0.5.21: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +stable-hash@^0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz" + integrity sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA== + +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + +string.prototype.includes@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz" + integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + +string.prototype.matchall@^4.0.12: + version "4.0.12" + resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz" + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + regexp.prototype.flags "^1.5.3" + set-function-name "^2.0.2" + side-channel "^1.1.0" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-2.1.2.tgz#a5e00ba66ab25f9cafa3726b567ce7a49170937a" + integrity sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ== + +styled-jsx@5.1.6: + version "5.1.6" + resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== + dependencies: + client-only "0.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +sweetalert2@^11.26.17: + version "11.26.17" + resolved "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.26.17.tgz" + integrity sha512-kkaySn1IRfwNlf9AkZVqDmBINDWw9NRR6Ij0O5dBRBOD1+mbtZJWxxR9/pA90nce9E5tIIkJ7SWij4rMWXtA1g== + +tailwindcss@4.1.18, tailwindcss@^4: + version "4.1.18" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz" + integrity sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw== + +tapable@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz" + integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== + +tinyglobby@^0.2.13, tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + +typescript-eslint@^8.46.0: + version "8.52.0" + resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.52.0.tgz" + integrity sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.52.0" + "@typescript-eslint/parser" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + +typescript@^5: + version "5.9.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +unrs-resolver@^1.6.2: + version "1.11.1" + resolved "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" + +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +"zod-validation-error@^3.5.0 || ^4.0.0": + version "4.0.2" + resolved "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz" + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== + +"zod@^3.25.0 || ^4.0.0", zod@^4.1.12: + version "4.3.5" + resolved "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz" + integrity sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==