mirror of
https://github.com/yusufipk/RepoHub.git
synced 2026-09-11 18:46:07 +00:00
docs: Add comprehensive package contribution guide and validation tooling
- Add bilingual README with English/Turkish language switcher - Create detailed package contribution guidelines with platform-specific naming conventions - Add validation script for verifying package presets against database - Include best practices and example PR format for contributors - Add tsx dependency for running TypeScript validation scripts - Document validation workflow with manual and automated verification options
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
# RepoHub - Cross-Platform Package Manager
|
# RepoHub - Cross-Platform Package Manager
|
||||||
|
|
||||||
|
**🇬🇧 English** | [🇹🇷 Türkçe](./README.tr.md)
|
||||||
|
|
||||||
**Simplify software installation across Linux, Windows, and macOS with official repositories.**
|
**Simplify software installation across Linux, Windows, and macOS with official repositories.**
|
||||||
|
|
||||||
RepoHub provides a unified interface for package discovery and installation across different operating systems.
|
RepoHub provides a unified interface for package discovery and installation across different operating systems.
|
||||||
@@ -96,6 +98,149 @@ curl -X POST http://localhost:3000/api/sync \
|
|||||||
-d '{"platform": "all"}'
|
-d '{"platform": "all"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 📦 Contributing to Package Recommendations
|
||||||
|
|
||||||
|
[🇹🇷 Türkçe README](./README.tr.md) | **🇬🇧 English**
|
||||||
|
|
||||||
|
RepoHub uses curated package lists to provide personalized recommendations to users. You can help improve these recommendations by adding packages!
|
||||||
|
|
||||||
|
### How to Add Packages
|
||||||
|
|
||||||
|
Package recommendations are stored in `/src/data/recommendationPresets.ts`. Here's how to add a package:
|
||||||
|
|
||||||
|
#### 1. Find the Right Location
|
||||||
|
|
||||||
|
Navigate to the platform and category where your package belongs:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export const PACKAGE_PRESETS = {
|
||||||
|
windows: {
|
||||||
|
development: ["Git.Git", "Microsoft.VisualStudioCode"],
|
||||||
|
design: ["GIMP.GIMP", "Inkscape.Inkscape"],
|
||||||
|
// ... other categories
|
||||||
|
},
|
||||||
|
// ... other platforms
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Available Platforms:**
|
||||||
|
- `windows` - Windows (Winget)
|
||||||
|
- `macos` - macOS (Homebrew)
|
||||||
|
- `ubuntu` - Ubuntu (APT)
|
||||||
|
- `debian` - Debian (APT)
|
||||||
|
- `arch` - Arch Linux (Pacman/AUR)
|
||||||
|
- `fedora` - Fedora (DNF)
|
||||||
|
|
||||||
|
**Available Categories:**
|
||||||
|
- `development` - Dev tools, IDEs, compilers
|
||||||
|
- `design` - Graphics, creative software
|
||||||
|
- `multimedia` - Media players, editors
|
||||||
|
- `system-tools` - System utilities
|
||||||
|
- `gaming` - Game launchers, platforms
|
||||||
|
- `productivity` - Office, browsers, productivity apps
|
||||||
|
- `education` - Educational software
|
||||||
|
|
||||||
|
#### 2. Get the Correct Package Name
|
||||||
|
|
||||||
|
**⚠️ CRITICAL:** Package names must match **exactly** as they appear in the database.
|
||||||
|
|
||||||
|
**Package name formats by platform:**
|
||||||
|
|
||||||
|
- **Windows**: `Publisher.PackageName` (e.g., `Microsoft.VisualStudioCode`)
|
||||||
|
- **macOS**: lowercase-with-hyphens (e.g., `visual-studio-code`)
|
||||||
|
- **Linux**: lowercase, varies by distro (e.g., `code`, `docker.io`)
|
||||||
|
|
||||||
|
#### 3. Verify the Package Exists
|
||||||
|
|
||||||
|
**Option A: Using the Validation Script (Recommended)**
|
||||||
|
|
||||||
|
If you have access to the database:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Validate specific platform
|
||||||
|
npm run validate:presets -- windows
|
||||||
|
|
||||||
|
# Validate multiple platforms
|
||||||
|
npm run validate:presets -- ubuntu debian arch
|
||||||
|
|
||||||
|
# Validate all platforms
|
||||||
|
npm run validate:presets -- --all
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will show:
|
||||||
|
- ✅ Packages found in database
|
||||||
|
- ❌ Packages not found
|
||||||
|
- 💡 Similar package suggestions
|
||||||
|
|
||||||
|
**Option B: Manual Verification**
|
||||||
|
|
||||||
|
If you don't have database access:
|
||||||
|
|
||||||
|
1. Search on the live RepoHub website
|
||||||
|
2. Find your package in the search results
|
||||||
|
3. Copy the **exact package name** displayed
|
||||||
|
4. Or check official package repositories:
|
||||||
|
- Windows: [winget.run](https://winget.run/)
|
||||||
|
- macOS: `brew search <package>`
|
||||||
|
- Ubuntu/Debian: `apt search <package>`
|
||||||
|
- Arch: [archlinux.org/packages](https://archlinux.org/packages/)
|
||||||
|
- Fedora: [packages.fedoraproject.org](https://packages.fedoraproject.org/)
|
||||||
|
|
||||||
|
#### 4. Add the Package
|
||||||
|
|
||||||
|
Simply add the package name to the array:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
windows: {
|
||||||
|
development: [
|
||||||
|
"Git.Git",
|
||||||
|
"Microsoft.VisualStudioCode",
|
||||||
|
"Docker.DockerDesktop" // ← Your new package
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Test Your Changes
|
||||||
|
|
||||||
|
1. Run validation:
|
||||||
|
```bash
|
||||||
|
npm run validate:presets -- windows
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the dev server:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Test in the app:
|
||||||
|
- Complete onboarding
|
||||||
|
- Select the relevant category
|
||||||
|
- Check if your package appears in recommendations
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
**DO ✅**
|
||||||
|
- Verify package names using the validation script
|
||||||
|
- Add popular, well-maintained packages
|
||||||
|
- Test before submitting
|
||||||
|
- Use exact package names from official repos
|
||||||
|
|
||||||
|
**DON'T ❌**
|
||||||
|
- Don't guess package names
|
||||||
|
- Don't add deprecated packages
|
||||||
|
- Don't skip verification
|
||||||
|
- Don't add duplicates across categories
|
||||||
|
|
||||||
|
### Example Pull Request
|
||||||
|
|
||||||
|
```
|
||||||
|
Add Popular Development Tools to Windows Recommendations
|
||||||
|
|
||||||
|
- Added Docker.DockerDesktop to development
|
||||||
|
- Added Postman.Postman to development
|
||||||
|
- Validation: ✅ All packages verified (100% found)
|
||||||
|
```
|
||||||
|
|
||||||
## 🤝 Contributing
|
## 🤝 Contributing
|
||||||
|
|
||||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||||
|
|||||||
+252
@@ -0,0 +1,252 @@
|
|||||||
|
# RepoHub - Çok Platformlu Paket Yöneticisi
|
||||||
|
|
||||||
|
[🇬🇧 English](./README.md) | **🇹🇷 Türkçe**
|
||||||
|
|
||||||
|
**Linux, Windows ve macOS'te resmi depolardan yazılım kurulumunu basitleştirin.**
|
||||||
|
|
||||||
|
RepoHub, farklı işletim sistemlerinde paket keşfi ve kurulumu için birleşik bir arayüz sağlar.
|
||||||
|
|
||||||
|
## 🚀 Özellikler
|
||||||
|
|
||||||
|
- **Çok Platformlu Destek**: Linux (Debian, Ubuntu, Arch, Fedora), Windows ve macOS'te çalışır.
|
||||||
|
- **Resmi Depolar**: Yazılımlara yalnızca güvenilir, resmi kaynaklardan erişin.
|
||||||
|
- **Script Oluşturma**: Seçtiğiniz platform için idempotent kurulum scriptleri oluşturun.
|
||||||
|
- **Akıllı Filtreleme**: Paketleri verimli bir şekilde bulun ve filtreleyin.
|
||||||
|
|
||||||
|
## 🛠️ Teknoloji Yığını
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- **Framework**: Next.js 14+ (React)
|
||||||
|
- **Stil**: Tailwind CSS
|
||||||
|
- **İkonlar**: Lucide React
|
||||||
|
- **Durum Yönetimi**: React Query + Zustand
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
- **Runtime**: Node.js (TypeScript)
|
||||||
|
- **Veritabanı**: PostgreSQL
|
||||||
|
- **Altyapı**: Docker
|
||||||
|
|
||||||
|
## 🏁 Başlangıç
|
||||||
|
|
||||||
|
### Gereksinimler
|
||||||
|
|
||||||
|
- Node.js 18+
|
||||||
|
- pnpm
|
||||||
|
- Docker (isteğe bağlı, veritabanı için)
|
||||||
|
|
||||||
|
### Kurulum
|
||||||
|
|
||||||
|
1. **Depoyu klonlayın:**
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yusufipk/RepoHub.git
|
||||||
|
cd RepoHub
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Bağımlılıkları yükleyin:**
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Ortam Değişkenlerini Ayarlayın:**
|
||||||
|
`.env.example` dosyasını `.env` olarak kopyalayın ve veritabanı bağlantınızı yapılandırın.
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Veritabanını Başlatın:**
|
||||||
|
Veritabanı şemasını kurmak ve migrasyonları uygulamak için başlatma scriptini çalıştırın.
|
||||||
|
```bash
|
||||||
|
pnpm init:db
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Geliştirme sunucusunu çalıştırın:**
|
||||||
|
```bash
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Tarayıcınızda [http://localhost:3000](http://localhost:3000) adresini açın.
|
||||||
|
|
||||||
|
## 🔄 API Kullanımı
|
||||||
|
|
||||||
|
### Depoları Senkronize Etme
|
||||||
|
|
||||||
|
API kullanarak depo senkronizasyonunu tetikleyebilirsiniz. Bu, paket veritabanını güncellemek için kullanışlıdır.
|
||||||
|
|
||||||
|
**Endpoint:** `POST /api/sync`
|
||||||
|
|
||||||
|
**Başlıklar:**
|
||||||
|
- `Content-Type`: `application/json`
|
||||||
|
- `x-sync-secret`: Senkronizasyon gizli anahtarınız (`SYNC_SERVER_ONLY=true` ise gerekli)
|
||||||
|
|
||||||
|
**Body Parametreleri:**
|
||||||
|
- `platform`: Senkronize edilecek platform. Seçenekler:
|
||||||
|
- `debian`: Debian paketlerini senkronize et (Resmi Repo)
|
||||||
|
- `ubuntu`: Ubuntu paketlerini senkronize et (Resmi Repo)
|
||||||
|
- `arch`: Arch Linux paketlerini senkronize et (Resmi Repo)
|
||||||
|
- `aur`: Arch User Repository (AUR) paketlerini senkronize et
|
||||||
|
- `fedora`: Fedora paketlerini senkronize et (Resmi Repo)
|
||||||
|
- `windows`: Windows paketlerini senkronize et (Winget)
|
||||||
|
- `macos`: macOS paketlerini senkronize et (Homebrew)
|
||||||
|
- `all`: Tüm platformları senkronize et
|
||||||
|
|
||||||
|
**Örnek İstek:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/sync \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "x-sync-secret: gizli_anahtariniz" \
|
||||||
|
-d '{"platform": "all"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📦 Paket Önerilerine Katkıda Bulunma
|
||||||
|
|
||||||
|
[🇬🇧 English](./README.md) | **🇹🇷 Türkçe**
|
||||||
|
|
||||||
|
RepoHub, kullanıcılara kişiselleştirilmiş öneriler sunmak için düzenlenmiş paket listeleri kullanır. Paket ekleyerek bu önerileri geliştirmeye yardımcı olabilirsiniz!
|
||||||
|
|
||||||
|
### Paket Nasıl Eklenir
|
||||||
|
|
||||||
|
Paket önerileri `/src/data/recommendationPresets.ts` dosyasında saklanır. İşte bir paket ekleme adımları:
|
||||||
|
|
||||||
|
#### 1. Doğru Konumu Bulun
|
||||||
|
|
||||||
|
Paketinizin ait olduğu platform ve kategoriye gidin:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export const PACKAGE_PRESETS = {
|
||||||
|
windows: {
|
||||||
|
development: ["Git.Git", "Microsoft.VisualStudioCode"],
|
||||||
|
design: ["GIMP.GIMP", "Inkscape.Inkscape"],
|
||||||
|
// ... diğer kategoriler
|
||||||
|
},
|
||||||
|
// ... diğer platformlar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Mevcut Platformlar:**
|
||||||
|
- `windows` - Windows (Winget)
|
||||||
|
- `macos` - macOS (Homebrew)
|
||||||
|
- `ubuntu` - Ubuntu (APT)
|
||||||
|
- `debian` - Debian (APT)
|
||||||
|
- `arch` - Arch Linux (Pacman/AUR)
|
||||||
|
- `fedora` - Fedora (DNF)
|
||||||
|
|
||||||
|
**Mevcut Kategoriler:**
|
||||||
|
- `development` - Geliştirme araçları, IDE'ler, derleyiciler
|
||||||
|
- `design` - Grafik, kreatif yazılımlar
|
||||||
|
- `multimedia` - Medya oynatıcılar, editörler
|
||||||
|
- `system-tools` - Sistem araçları
|
||||||
|
- `gaming` - Oyun başlatıcıları, platformlar
|
||||||
|
- `productivity` - Ofis, tarayıcılar, üretkenlik uygulamaları
|
||||||
|
- `education` - Eğitim yazılımları
|
||||||
|
|
||||||
|
#### 2. Doğru Paket Adını Alın
|
||||||
|
|
||||||
|
**⚠️ KRİTİK:** Paket adları veritabanında göründükleri gibi **tam olarak** eşleşmelidir.
|
||||||
|
|
||||||
|
**Platformlara göre paket adı formatları:**
|
||||||
|
|
||||||
|
- **Windows**: `Yayinci.PaketAdi` (örn., `Microsoft.VisualStudioCode`)
|
||||||
|
- **macOS**: kucuk-harf-tireli (örn., `visual-studio-code`)
|
||||||
|
- **Linux**: küçük harf, dağıtıma göre değişir (örn., `code`, `docker.io`)
|
||||||
|
|
||||||
|
#### 3. Paketin Var Olduğunu Doğrulayın
|
||||||
|
|
||||||
|
**Seçenek A: Doğrulama Scriptini Kullanma (Önerilen)**
|
||||||
|
|
||||||
|
Veritabanı erişiminiz varsa:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Belirli bir platformu doğrula
|
||||||
|
npm run validate:presets -- windows
|
||||||
|
|
||||||
|
# Birden fazla platformu doğrula
|
||||||
|
npm run validate:presets -- ubuntu debian arch
|
||||||
|
|
||||||
|
# Tüm platformları doğrula
|
||||||
|
npm run validate:presets -- --all
|
||||||
|
```
|
||||||
|
|
||||||
|
Script şunları gösterecek:
|
||||||
|
- ✅ Veritabanında bulunan paketler
|
||||||
|
- ❌ Bulunamayan paketler
|
||||||
|
- 💡 Benzer paket önerileri
|
||||||
|
|
||||||
|
**Seçenek B: Manuel Doğrulama**
|
||||||
|
|
||||||
|
Veritabanı erişiminiz yoksa:
|
||||||
|
|
||||||
|
1. Canlı RepoHub web sitesinde arama yapın
|
||||||
|
2. Arama sonuçlarında paketinizi bulun
|
||||||
|
3. Görüntülenen **tam paket adını** kopyalayın
|
||||||
|
4. Veya resmi paket depolarını kontrol edin:
|
||||||
|
- Windows: [winget.run](https://winget.run/)
|
||||||
|
- macOS: `brew search <paket>`
|
||||||
|
- Ubuntu/Debian: `apt search <paket>`
|
||||||
|
- Arch: [archlinux.org/packages](https://archlinux.org/packages/)
|
||||||
|
- Fedora: [packages.fedoraproject.org](https://packages.fedoraproject.org/)
|
||||||
|
|
||||||
|
#### 4. Paketi Ekleyin
|
||||||
|
|
||||||
|
Paket adını diziye ekleyin:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
windows: {
|
||||||
|
development: [
|
||||||
|
"Git.Git",
|
||||||
|
"Microsoft.VisualStudioCode",
|
||||||
|
"Docker.DockerDesktop" // ← Yeni paketiniz
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Değişikliklerinizi Test Edin
|
||||||
|
|
||||||
|
1. Doğrulamayı çalıştırın:
|
||||||
|
```bash
|
||||||
|
npm run validate:presets -- windows
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Geliştirme sunucusunu başlatın:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Uygulamada test edin:
|
||||||
|
- Onboarding'i tamamlayın
|
||||||
|
- İlgili kategoriyi seçin
|
||||||
|
- Paketinizin önerilerde görünüp görünmediğini kontrol edin
|
||||||
|
|
||||||
|
### En İyi Uygulamalar
|
||||||
|
|
||||||
|
**YAPIN ✅**
|
||||||
|
- Doğrulama scriptini kullanarak paket adlarını doğrulayın
|
||||||
|
- Popüler, iyi bakımlı paketler ekleyin
|
||||||
|
- Göndermeden önce test edin
|
||||||
|
- Resmi depolardan tam paket adlarını kullanın
|
||||||
|
|
||||||
|
**YAPMAYIN ❌**
|
||||||
|
- Paket adlarını tahmin etmeyin
|
||||||
|
- Kullanımdan kaldırılmış paketler eklemeyin
|
||||||
|
- Doğrulamayı atlamayın
|
||||||
|
- Kategoriler arasında tekrar eklemeyin
|
||||||
|
|
||||||
|
### Örnek Pull Request
|
||||||
|
|
||||||
|
```
|
||||||
|
Windows Önerilerine Popüler Geliştirme Araçları Eklendi
|
||||||
|
|
||||||
|
- development'a Docker.DockerDesktop eklendi
|
||||||
|
- development'a Postman.Postman eklendi
|
||||||
|
- Doğrulama: ✅ Tüm paketler doğrulandı (%100 bulundu)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🤝 Katkıda Bulunma
|
||||||
|
|
||||||
|
Katkılar hoş karşılanır! Lütfen Pull Request göndermekten çekinmeyin.
|
||||||
|
|
||||||
|
1. Projeyi fork edin
|
||||||
|
2. Feature branch'inizi oluşturun (`git checkout -b feature/HarikaBirOzellik`)
|
||||||
|
3. Değişikliklerinizi commit edin (`git commit -m 'Harika bir özellik ekle'`)
|
||||||
|
4. Branch'inizi push edin (`git push origin feature/HarikaBirOzellik`)
|
||||||
|
5. Bir Pull Request açın
|
||||||
+3
-1
@@ -9,7 +9,8 @@
|
|||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"test:db": "node scripts/test-db.js",
|
"test:db": "node scripts/test-db.js",
|
||||||
"init:db": "node scripts/init-db.js"
|
"init:db": "node scripts/init-db.js",
|
||||||
|
"validate:presets": "tsx scripts/validate-presets.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"tailwind-merge": "^2.1.0",
|
"tailwind-merge": "^2.1.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"tsx": "^4.20.6",
|
||||||
"undici": "^6.6.2",
|
"undici": "^6.6.2",
|
||||||
"zustand": "^4.4.7"
|
"zustand": "^4.4.7"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+291
-7
@@ -64,7 +64,10 @@ importers:
|
|||||||
version: 2.6.0
|
version: 2.6.0
|
||||||
tailwindcss-animate:
|
tailwindcss-animate:
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7([email protected])
|
version: 1.0.7([email protected]([email protected]))
|
||||||
|
tsx:
|
||||||
|
specifier: ^4.20.6
|
||||||
|
version: 4.20.6
|
||||||
undici:
|
undici:
|
||||||
specifier: ^6.6.2
|
specifier: ^6.6.2
|
||||||
version: 6.22.0
|
version: 6.22.0
|
||||||
@@ -98,7 +101,7 @@ importers:
|
|||||||
version: 8.5.6
|
version: 8.5.6
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.3.0
|
specifier: ^3.3.0
|
||||||
version: 3.4.18
|
version: 3.4.18([email protected])
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5
|
specifier: ^5
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
@@ -122,6 +125,162 @@ packages:
|
|||||||
'@emnapi/[email protected]':
|
'@emnapi/[email protected]':
|
||||||
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
|
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@eslint-community/[email protected]':
|
'@eslint-community/[email protected]':
|
||||||
resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
|
resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
@@ -1166,6 +1325,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
|
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2314,6 +2478,11 @@ packages:
|
|||||||
[email protected]:
|
[email protected]:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -2494,6 +2663,84 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/[email protected]':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@eslint-community/[email protected]([email protected])':
|
'@eslint-community/[email protected]([email protected])':
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
@@ -3589,6 +3836,35 @@ snapshots:
|
|||||||
is-date-object: 1.1.0
|
is-date-object: 1.1.0
|
||||||
is-symbol: 1.1.1
|
is-symbol: 1.1.1
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
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
|
||||||
|
|
||||||
[email protected]: {}
|
[email protected]: {}
|
||||||
|
|
||||||
[email protected]: {}
|
[email protected]: {}
|
||||||
@@ -4463,12 +4739,13 @@ snapshots:
|
|||||||
camelcase-css: 2.0.1
|
camelcase-css: 2.0.1
|
||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
|
|
||||||
[email protected]([email protected])([email protected]):
|
[email protected]([email protected])([email protected])([email protected]):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.3
|
lilconfig: 3.1.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
jiti: 1.21.7
|
jiti: 1.21.7
|
||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
|
tsx: 4.20.6
|
||||||
|
|
||||||
[email protected]([email protected]):
|
[email protected]([email protected]):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4819,11 +5096,11 @@ snapshots:
|
|||||||
|
|
||||||
[email protected]: {}
|
[email protected]: {}
|
||||||
|
|
||||||
[email protected]([email protected]):
|
[email protected]([email protected]([email protected])):
|
||||||
dependencies:
|
dependencies:
|
||||||
tailwindcss: 3.4.18
|
tailwindcss: 3.4.18([email protected])
|
||||||
|
|
||||||
[email protected]:
|
[email protected]([email protected]):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
arg: 5.0.2
|
arg: 5.0.2
|
||||||
@@ -4842,7 +5119,7 @@ snapshots:
|
|||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
postcss-import: 15.1.0([email protected])
|
postcss-import: 15.1.0([email protected])
|
||||||
postcss-js: 4.1.0([email protected])
|
postcss-js: 4.1.0([email protected])
|
||||||
postcss-load-config: 6.0.1([email protected])([email protected])
|
postcss-load-config: 6.0.1([email protected])([email protected])([email protected])
|
||||||
postcss-nested: 6.2.0([email protected])
|
postcss-nested: 6.2.0([email protected])
|
||||||
postcss-selector-parser: 6.1.2
|
postcss-selector-parser: 6.1.2
|
||||||
resolve: 1.22.11
|
resolve: 1.22.11
|
||||||
@@ -4885,6 +5162,13 @@ snapshots:
|
|||||||
|
|
||||||
[email protected]: {}
|
[email protected]: {}
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.25.12
|
||||||
|
get-tsconfig: 4.13.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
|
|||||||
Executable
+188
@@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate package names in recommendation presets against the database
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node scripts/validate-presets.js --all
|
||||||
|
* node scripts/validate-presets.js windows macos
|
||||||
|
* node scripts/validate-presets.js ubuntu
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
// Import the presets
|
||||||
|
const { PACKAGE_PRESETS } = require('../src/data/recommendationPresets.ts');
|
||||||
|
|
||||||
|
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
|
||||||
|
|
||||||
|
// Platform IDs
|
||||||
|
const PLATFORMS = ['windows', 'macos', 'ubuntu', 'debian', 'arch', 'fedora'];
|
||||||
|
|
||||||
|
async function checkPackageExists(platformId, packageName) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${API_BASE_URL}/api/packages?platform_id=${platformId}&search=${encodeURIComponent(packageName)}&limit=10`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`API error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Check for exact match (case-insensitive)
|
||||||
|
const exactMatch = data.packages?.find(
|
||||||
|
pkg => pkg.name.toLowerCase() === packageName.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
exists: !!exactMatch,
|
||||||
|
foundName: exactMatch?.name || null,
|
||||||
|
similarMatches: data.packages?.slice(0, 3).map(p => p.name) || []
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error checking ${packageName} on ${platformId}:`, error.message);
|
||||||
|
return { exists: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validatePlatform(platformId) {
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log(`Validating ${platformId.toUpperCase()}`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
const platformPresets = PACKAGE_PRESETS[platformId];
|
||||||
|
if (!platformPresets) {
|
||||||
|
console.log(`❌ No presets found for platform: ${platformId}`);
|
||||||
|
return { total: 0, found: 0, missing: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
total: 0,
|
||||||
|
found: 0,
|
||||||
|
missing: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check each category
|
||||||
|
for (const [category, packages] of Object.entries(platformPresets)) {
|
||||||
|
console.log(`\n📁 Category: ${category}`);
|
||||||
|
|
||||||
|
for (const packageName of packages) {
|
||||||
|
results.total++;
|
||||||
|
|
||||||
|
const check = await checkPackageExists(platformId, packageName);
|
||||||
|
|
||||||
|
if (check.error) {
|
||||||
|
console.log(` ⚠️ ${packageName} - Error: ${check.error}`);
|
||||||
|
results.missing.push({ category, packageName, reason: 'API Error' });
|
||||||
|
} else if (check.exists) {
|
||||||
|
console.log(` ✅ ${packageName}${check.foundName !== packageName ? ` (found as: ${check.foundName})` : ''}`);
|
||||||
|
results.found++;
|
||||||
|
} else {
|
||||||
|
console.log(` ❌ ${packageName} - NOT FOUND`);
|
||||||
|
if (check.similarMatches?.length > 0) {
|
||||||
|
console.log(` Similar: ${check.similarMatches.join(', ')}`);
|
||||||
|
}
|
||||||
|
results.missing.push({
|
||||||
|
category,
|
||||||
|
packageName,
|
||||||
|
similar: check.similarMatches
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small delay to avoid overwhelming the API
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
console.log('Usage:');
|
||||||
|
console.log(' node scripts/validate-presets.js --all');
|
||||||
|
console.log(' node scripts/validate-presets.js windows macos ubuntu');
|
||||||
|
console.log('\nAvailable platforms:', PLATFORMS.join(', '));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let platformsToCheck = [];
|
||||||
|
|
||||||
|
if (args.includes('--all')) {
|
||||||
|
platformsToCheck = PLATFORMS;
|
||||||
|
} else {
|
||||||
|
// Validate platform names
|
||||||
|
for (const platform of args) {
|
||||||
|
if (!PLATFORMS.includes(platform)) {
|
||||||
|
console.error(`❌ Invalid platform: ${platform}`);
|
||||||
|
console.log('Available platforms:', PLATFORMS.join(', '));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
platformsToCheck = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n🔍 Validating package presets for: ${platformsToCheck.join(', ')}\n`);
|
||||||
|
|
||||||
|
const allResults = {};
|
||||||
|
|
||||||
|
for (const platform of platformsToCheck) {
|
||||||
|
const results = await validatePlatform(platform);
|
||||||
|
allResults[platform] = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log('SUMMARY');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
let totalPackages = 0;
|
||||||
|
let totalFound = 0;
|
||||||
|
let totalMissing = 0;
|
||||||
|
|
||||||
|
for (const [platform, results] of Object.entries(allResults)) {
|
||||||
|
totalPackages += results.total;
|
||||||
|
totalFound += results.found;
|
||||||
|
totalMissing += results.missing.length;
|
||||||
|
|
||||||
|
const successRate = results.total > 0
|
||||||
|
? ((results.found / results.total) * 100).toFixed(1)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
console.log(`\n${platform.toUpperCase()}:`);
|
||||||
|
console.log(` Total: ${results.total}`);
|
||||||
|
console.log(` Found: ${results.found} (${successRate}%)`);
|
||||||
|
console.log(` Missing: ${results.missing.length}`);
|
||||||
|
|
||||||
|
if (results.missing.length > 0) {
|
||||||
|
console.log(` Missing packages:`);
|
||||||
|
for (const { category, packageName, similar } of results.missing) {
|
||||||
|
console.log(` - ${packageName} (${category})`);
|
||||||
|
if (similar?.length > 0) {
|
||||||
|
console.log(` Try: ${similar.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log(`OVERALL: ${totalFound}/${totalPackages} packages found (${((totalFound / totalPackages) * 100).toFixed(1)}%)`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
if (totalMissing > 0) {
|
||||||
|
console.log(`\n⚠️ Found ${totalMissing} missing packages. Review the output above and update recommendationPresets.ts`);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
console.log('\n✅ All packages validated successfully!');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(error => {
|
||||||
|
console.error('Fatal error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
/**
|
||||||
|
* Validate package names in recommendation presets against the database
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* tsx scripts/validate-presets.ts --all
|
||||||
|
* tsx scripts/validate-presets.ts windows macos
|
||||||
|
* tsx scripts/validate-presets.ts ubuntu
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PACKAGE_PRESETS } from '../src/data/recommendationPresets';
|
||||||
|
|
||||||
|
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3002';
|
||||||
|
|
||||||
|
// Platform IDs
|
||||||
|
const PLATFORMS = ['windows', 'macos', 'ubuntu', 'debian', 'arch', 'fedora'] as const;
|
||||||
|
type PlatformId = typeof PLATFORMS[number];
|
||||||
|
|
||||||
|
interface PackageCheckResult {
|
||||||
|
exists: boolean;
|
||||||
|
foundName?: string;
|
||||||
|
similarMatches?: string[];
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkPackageExists(
|
||||||
|
platformId: string,
|
||||||
|
packageName: string
|
||||||
|
): Promise<PackageCheckResult> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${API_BASE_URL}/api/packages?platform_id=${platformId}&search=${encodeURIComponent(packageName)}&limit=10`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`API error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Check for exact match (case-insensitive)
|
||||||
|
const exactMatch = data.packages?.find(
|
||||||
|
(pkg: any) => pkg.name.toLowerCase() === packageName.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
exists: !!exactMatch,
|
||||||
|
foundName: exactMatch?.name || undefined,
|
||||||
|
similarMatches: data.packages?.slice(0, 3).map((p: any) => p.name) || []
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`Error checking ${packageName} on ${platformId}:`, error.message);
|
||||||
|
return { exists: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validatePlatform(platformId: PlatformId) {
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log(`Validating ${platformId.toUpperCase()}`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
const platformPresets = PACKAGE_PRESETS[platformId];
|
||||||
|
if (!platformPresets) {
|
||||||
|
console.log(`❌ No presets found for platform: ${platformId}`);
|
||||||
|
return { total: 0, found: 0, missing: [] as any[] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
total: 0,
|
||||||
|
found: 0,
|
||||||
|
missing: [] as { category: string; packageName: string; similar?: string[]; reason?: string }[]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check each category
|
||||||
|
for (const [category, packages] of Object.entries(platformPresets)) {
|
||||||
|
console.log(`\n📁 Category: ${category}`);
|
||||||
|
|
||||||
|
for (const packageName of packages) {
|
||||||
|
results.total++;
|
||||||
|
|
||||||
|
const check = await checkPackageExists(platformId, packageName);
|
||||||
|
|
||||||
|
if (check.error) {
|
||||||
|
console.log(` ⚠️ ${packageName} - Error: ${check.error}`);
|
||||||
|
results.missing.push({ category, packageName, reason: 'API Error' });
|
||||||
|
} else if (check.exists) {
|
||||||
|
console.log(` ✅ ${packageName}${check.foundName !== packageName ? ` (found as: ${check.foundName})` : ''}`);
|
||||||
|
results.found++;
|
||||||
|
} else {
|
||||||
|
console.log(` ❌ ${packageName} - NOT FOUND`);
|
||||||
|
if (check.similarMatches && check.similarMatches.length > 0) {
|
||||||
|
console.log(` Similar: ${check.similarMatches.join(', ')}`);
|
||||||
|
}
|
||||||
|
results.missing.push({
|
||||||
|
category,
|
||||||
|
packageName,
|
||||||
|
similar: check.similarMatches
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay to avoid rate limiting
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
console.log('Usage:');
|
||||||
|
console.log(' tsx scripts/validate-presets.ts --all');
|
||||||
|
console.log(' tsx scripts/validate-presets.ts windows macos ubuntu');
|
||||||
|
console.log('\nAvailable platforms:', PLATFORMS.join(', '));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let platformsToCheck: PlatformId[] = [];
|
||||||
|
|
||||||
|
if (args.includes('--all')) {
|
||||||
|
platformsToCheck = [...PLATFORMS];
|
||||||
|
} else {
|
||||||
|
// Validate platform names
|
||||||
|
for (const platform of args) {
|
||||||
|
if (!PLATFORMS.includes(platform as any)) {
|
||||||
|
console.error(`❌ Invalid platform: ${platform}`);
|
||||||
|
console.log('Available platforms:', PLATFORMS.join(', '));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
platformsToCheck = args as PlatformId[];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n🔍 Validating package presets for: ${platformsToCheck.join(', ')}\n`);
|
||||||
|
|
||||||
|
const allResults: Record<string, any> = {};
|
||||||
|
|
||||||
|
for (const platform of platformsToCheck) {
|
||||||
|
const results = await validatePlatform(platform);
|
||||||
|
allResults[platform] = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log('SUMMARY');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
let totalPackages = 0;
|
||||||
|
let totalFound = 0;
|
||||||
|
let totalMissing = 0;
|
||||||
|
|
||||||
|
for (const [platform, results] of Object.entries(allResults)) {
|
||||||
|
totalPackages += results.total;
|
||||||
|
totalFound += results.found;
|
||||||
|
totalMissing += results.missing.length;
|
||||||
|
|
||||||
|
const successRate = results.total > 0
|
||||||
|
? ((results.found / results.total) * 100).toFixed(1)
|
||||||
|
: '0';
|
||||||
|
|
||||||
|
console.log(`\n${platform.toUpperCase()}:`);
|
||||||
|
console.log(` Total: ${results.total}`);
|
||||||
|
console.log(` Found: ${results.found} (${successRate}%)`);
|
||||||
|
console.log(` Missing: ${results.missing.length}`);
|
||||||
|
|
||||||
|
if (results.missing.length > 0) {
|
||||||
|
console.log(` Missing packages:`);
|
||||||
|
for (const { category, packageName, similar } of results.missing) {
|
||||||
|
console.log(` - ${packageName} (${category})`);
|
||||||
|
if (similar && similar.length > 0) {
|
||||||
|
console.log(` Try: ${similar.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n${'='.repeat(60)}`);
|
||||||
|
console.log(`OVERALL: ${totalFound}/${totalPackages} packages found (${((totalFound / totalPackages) * 100).toFixed(1)}%)`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
if (totalMissing > 0) {
|
||||||
|
console.log(`\n⚠️ Found ${totalMissing} missing packages. Review the output above and update recommendationPresets.ts`);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
console.log('\n✅ All packages validated successfully!');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(error => {
|
||||||
|
console.error('Fatal error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -65,14 +65,14 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate and set limit with better error message
|
// Validate and set limit with better error message
|
||||||
if (body.limit !== undefined && (body.limit < 1 || body.limit > 50)) {
|
if (body.limit !== undefined && (body.limit < 1 || body.limit > 1000)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Limit must be between 1 and 50" },
|
{ error: "Limit must be between 1 and 1000" },
|
||||||
{ status: 400 }
|
{ status: 400 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const limit =
|
const limit =
|
||||||
body.limit && body.limit > 0 && body.limit <= 50 ? body.limit : 20;
|
body.limit && body.limit > 0 && body.limit <= 1000 ? body.limit : 50;
|
||||||
|
|
||||||
// Generate recommendations
|
// Generate recommendations
|
||||||
const recommendations = await RecommendationService.generateRecommendations(
|
const recommendations = await RecommendationService.generateRecommendations(
|
||||||
|
|||||||
@@ -174,12 +174,6 @@ export function OnboardingModal({
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedCategories.length > 0 && (
|
|
||||||
<p className="text-sm text-muted-foreground text-center">
|
|
||||||
{t('onboarding.step1.selected', { count: selectedCategories.length })}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,6 @@ export function RecommendationCard({ pkg, isSelected, onToggle }: Recommendation
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-muted-foreground line-clamp-2 mb-3">
|
|
||||||
{pkg.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={isSelected ? 'default' : 'outline'}
|
variant={isSelected ? 'default' : 'outline'}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export function RecommendationListItem({ pkg, isSelected, onToggle }: Recommenda
|
|||||||
<h4 className="font-semibold text-sm truncate">{pkg.name}</h4>
|
<h4 className="font-semibold text-sm truncate">{pkg.name}</h4>
|
||||||
<span className="text-xs text-muted-foreground">{pkg.version}</span>
|
<span className="text-xs text-muted-foreground">{pkg.version}</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground truncate">{pkg.description}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function RecommendationsSection({
|
|||||||
platform_id: getEffectiveOS(),
|
platform_id: getEffectiveOS(),
|
||||||
categories: effectiveProfile.categories,
|
categories: effectiveProfile.categories,
|
||||||
experienceLevel: effectiveProfile.experienceLevel,
|
experienceLevel: effectiveProfile.experienceLevel,
|
||||||
limit: 12
|
limit: 1000
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+470
-124
@@ -10,227 +10,374 @@ import { UserCategory } from "@/types/recommendations";
|
|||||||
type PlatformId = "windows" | "macos" | "ubuntu" | "debian" | "arch" | "fedora";
|
type PlatformId = "windows" | "macos" | "ubuntu" | "debian" | "arch" | "fedora";
|
||||||
|
|
||||||
export const PACKAGE_PRESETS: Record<PlatformId, Record<UserCategory, string[]>> = {
|
export const PACKAGE_PRESETS: Record<PlatformId, Record<UserCategory, string[]>> = {
|
||||||
windows: {
|
"windows": {
|
||||||
development: [
|
"development": [
|
||||||
"git",
|
"Git.Git",
|
||||||
"code", // Visual Studio Code
|
"Microsoft.VisualStudioCode",
|
||||||
"nodejs",
|
"Docker.DockerDesktop",
|
||||||
"python",
|
"Postman.Postman",
|
||||||
"docker-desktop",
|
"Microsoft.WindowsTerminal",
|
||||||
"postman",
|
"Microsoft.PowerShell",
|
||||||
|
"Notepad++.Notepad++",
|
||||||
|
"WinSCP.WinSCP",
|
||||||
|
"PuTTY.PuTTY",
|
||||||
|
"WinMerge.WinMerge",
|
||||||
|
"EclipseFoundation.Eclipse",
|
||||||
|
"Anysphere.Cursor"
|
||||||
],
|
],
|
||||||
design: [
|
"design": [
|
||||||
"gimp",
|
"GIMP.GIMP",
|
||||||
"inkscape",
|
"Inkscape.Inkscape",
|
||||||
"blender",
|
"BlenderFoundation.Blender",
|
||||||
|
"KDE.Krita",
|
||||||
|
"IrfanSkiljan.IrfanView",
|
||||||
|
"XnSoft.XnViewMP",
|
||||||
|
"FastStone.Viewer",
|
||||||
|
"Greenshot.Greenshot",
|
||||||
|
"ShareX.ShareX"
|
||||||
],
|
],
|
||||||
multimedia: [
|
"multimedia": [
|
||||||
"vlc",
|
"VideoLAN.VLC",
|
||||||
"audacity",
|
"Audacity.Audacity",
|
||||||
"obs-studio",
|
"OBSProject.OBSStudio",
|
||||||
|
"Apple.iTunes",
|
||||||
|
"AIMP.AIMP",
|
||||||
|
"PeterPawlowski.foobar2000",
|
||||||
|
"Winamp.Winamp",
|
||||||
|
"GOMLab.GOMPlayer",
|
||||||
|
"Spotify.Spotify",
|
||||||
|
"VentisMedia.MediaMonkey",
|
||||||
|
"HandBrake.HandBrake"
|
||||||
],
|
],
|
||||||
"system-tools": [
|
"system-tools": [
|
||||||
"7zip",
|
"7zip.7zip",
|
||||||
"powertoys",
|
"Microsoft.PowerToys",
|
||||||
"everything",
|
"voidtools.Everything",
|
||||||
|
"RARLab.WinRAR",
|
||||||
|
"DominikReichl.KeePass",
|
||||||
|
"TeamViewer.TeamViewer",
|
||||||
|
"RealVNC.VNCViewer",
|
||||||
|
"CodeSector.TeraCopy",
|
||||||
|
"LIGHTNINGUK.ImgBurn",
|
||||||
|
"WinDirStat.WinDirStat",
|
||||||
|
"AntibodySoftware.WizTree",
|
||||||
|
"Glarysoft.GlaryUtilities",
|
||||||
|
"ChristianKindahl.InfraRecorder",
|
||||||
|
"Open-Shell.Open-Shell-Menu",
|
||||||
|
"Piriform.CCleaner",
|
||||||
|
"Rufus.Rufus",
|
||||||
|
"BleachBit.BleachBit",
|
||||||
|
"NVAccess.NVDA",
|
||||||
|
"Malwarebytes.Malwarebytes",
|
||||||
|
"SUPERAntiSpyware.SUPERAntiSpyware",
|
||||||
|
"qBittorrent.qBittorrent"
|
||||||
],
|
],
|
||||||
gaming: [
|
"gaming": [
|
||||||
"steam",
|
"Valve.Steam",
|
||||||
"discord",
|
"Discord.Discord",
|
||||||
|
"EpicGames.EpicGamesLauncher",
|
||||||
|
"GOG.Galaxy"
|
||||||
],
|
],
|
||||||
productivity: [
|
"productivity": [
|
||||||
"notion",
|
"Notion.Notion",
|
||||||
"obsidian",
|
"Obsidian.Obsidian",
|
||||||
"slack",
|
"SlackTechnologies.Slack",
|
||||||
],
|
"Google.Chrome",
|
||||||
education: [
|
"Mozilla.Firefox",
|
||||||
"anki",
|
"Microsoft.Edge",
|
||||||
|
"Brave.Brave",
|
||||||
|
"Opera.Opera",
|
||||||
|
"Zoom.Zoom",
|
||||||
|
"Microsoft.Teams",
|
||||||
|
"Pidgin.Pidgin",
|
||||||
|
"Mozilla.Thunderbird",
|
||||||
|
"Foxit.FoxitReader",
|
||||||
|
"TheDocumentFoundation.LibreOffice",
|
||||||
|
"SumatraPDF.SumatraPDF",
|
||||||
|
"AcroSoftware.CutePDFWriter",
|
||||||
|
"Apache.OpenOffice",
|
||||||
|
"Dropbox.Dropbox",
|
||||||
|
"Microsoft.OneDrive",
|
||||||
|
"Google.EarthPro",
|
||||||
|
"Evernote.Evernote"
|
||||||
],
|
],
|
||||||
|
"education": [
|
||||||
|
"Anki.Anki"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
macos: {
|
"macos": {
|
||||||
development: [
|
"development": [
|
||||||
"git",
|
"git",
|
||||||
"code", // Visual Studio Code
|
"visual-studio-code",
|
||||||
"nodejs",
|
"cursor",
|
||||||
"python",
|
"node",
|
||||||
"docker",
|
|
||||||
"postman",
|
"postman",
|
||||||
|
"iterm2",
|
||||||
|
"warp",
|
||||||
|
"sublime-text",
|
||||||
|
"cyberduck",
|
||||||
|
"meld",
|
||||||
|
"dotnet-sdk",
|
||||||
|
"temurin"
|
||||||
],
|
],
|
||||||
design: [
|
"design": [
|
||||||
"gimp",
|
"gimp",
|
||||||
"inkscape",
|
"inkscape",
|
||||||
"blender",
|
"blender",
|
||||||
|
"krita",
|
||||||
|
"xnviewmp"
|
||||||
],
|
],
|
||||||
multimedia: [
|
"multimedia": [
|
||||||
"vlc",
|
"vlc",
|
||||||
"audacity",
|
"audacity",
|
||||||
"obs",
|
"obs",
|
||||||
|
"spotify",
|
||||||
|
"handbrake",
|
||||||
|
"iina",
|
||||||
|
"foobar2000"
|
||||||
],
|
],
|
||||||
"system-tools": [
|
"system-tools": [
|
||||||
"rectangle",
|
"rectangle",
|
||||||
"the-unarchiver",
|
"the-unarchiver",
|
||||||
|
"keka",
|
||||||
|
"appcleaner",
|
||||||
|
"keepassxc",
|
||||||
|
"teamviewer",
|
||||||
|
"anydesk",
|
||||||
|
"malwarebytes",
|
||||||
|
"raycast",
|
||||||
|
"alfred",
|
||||||
|
"qbittorrent"
|
||||||
],
|
],
|
||||||
gaming: [
|
"gaming": [
|
||||||
"steam",
|
"steam",
|
||||||
"discord",
|
"discord",
|
||||||
|
"epic-games"
|
||||||
],
|
],
|
||||||
productivity: [
|
"productivity": [
|
||||||
"notion",
|
"notion",
|
||||||
"obsidian",
|
"obsidian",
|
||||||
"slack",
|
"slack",
|
||||||
|
"zoom",
|
||||||
|
"microsoft-teams",
|
||||||
|
"thunderbird",
|
||||||
|
"google-chrome",
|
||||||
|
"firefox",
|
||||||
|
"microsoft-edge",
|
||||||
|
"brave-browser",
|
||||||
|
"opera",
|
||||||
|
"libreoffice",
|
||||||
|
"foxitreader",
|
||||||
|
"adobe-acrobat-reader",
|
||||||
|
"dropbox",
|
||||||
|
"google-drive",
|
||||||
|
"onedrive"
|
||||||
],
|
],
|
||||||
education: [
|
"education": [
|
||||||
"anki",
|
"anki",
|
||||||
],
|
"zotero"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
ubuntu: {
|
"ubuntu": {
|
||||||
development: [
|
"development": [
|
||||||
"git",
|
"git",
|
||||||
"code", // Visual Studio Code
|
|
||||||
"nodejs",
|
|
||||||
"python3",
|
|
||||||
"docker.io",
|
|
||||||
"curl",
|
"curl",
|
||||||
|
"wget",
|
||||||
|
"nodejs",
|
||||||
|
"npm",
|
||||||
|
"python3-pip",
|
||||||
|
"docker.io",
|
||||||
|
"dotnet-sdk-8.0"
|
||||||
],
|
],
|
||||||
design: [
|
"design": [
|
||||||
"gimp",
|
"gimp",
|
||||||
"inkscape",
|
"inkscape",
|
||||||
"blender",
|
"blender",
|
||||||
|
"krita",
|
||||||
|
"darktable"
|
||||||
],
|
],
|
||||||
multimedia: [
|
"multimedia": [
|
||||||
"vlc",
|
"vlc",
|
||||||
"audacity",
|
"audacity",
|
||||||
"obs-studio",
|
"obs-studio",
|
||||||
|
"ffmpeg",
|
||||||
|
"mpv",
|
||||||
|
"handbrake",
|
||||||
|
"kdenlive"
|
||||||
|
],
|
||||||
|
"system-tools": [
|
||||||
|
"neofetch",
|
||||||
|
"timeshift",
|
||||||
|
"stacer",
|
||||||
|
"keepassxc",
|
||||||
|
"synaptic"
|
||||||
|
],
|
||||||
|
"gaming": [
|
||||||
|
"steam",
|
||||||
|
"lutris",
|
||||||
|
"mangohud"
|
||||||
|
],
|
||||||
|
"productivity": [
|
||||||
|
"libreoffice",
|
||||||
|
"chromium-browser",
|
||||||
|
"evolution",
|
||||||
|
"focuswriter"
|
||||||
|
],
|
||||||
|
"education": [
|
||||||
|
"anki"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"debian": {
|
||||||
|
"development": [
|
||||||
|
"git",
|
||||||
|
"build-essential",
|
||||||
|
"curl",
|
||||||
|
"wget",
|
||||||
|
"nodejs",
|
||||||
|
"npm",
|
||||||
|
"python3",
|
||||||
|
"python3-pip",
|
||||||
|
"docker.io"
|
||||||
|
],
|
||||||
|
"design": [
|
||||||
|
"gimp",
|
||||||
|
"inkscape",
|
||||||
|
"blender",
|
||||||
|
"krita"
|
||||||
|
],
|
||||||
|
"multimedia": [
|
||||||
|
"vlc",
|
||||||
|
"audacity",
|
||||||
|
"obs-studio",
|
||||||
|
"ffmpeg",
|
||||||
|
"handbrake"
|
||||||
],
|
],
|
||||||
"system-tools": [
|
"system-tools": [
|
||||||
"htop",
|
"htop",
|
||||||
"neofetch",
|
"fastfetch",
|
||||||
"tldr",
|
"tmux",
|
||||||
|
"zsh",
|
||||||
|
"gparted",
|
||||||
|
"timeshift",
|
||||||
|
"keepassxc"
|
||||||
],
|
],
|
||||||
gaming: [
|
"gaming": [
|
||||||
"steam",
|
"steam",
|
||||||
"discord",
|
"lutris",
|
||||||
|
"gamemode",
|
||||||
|
"mangohud"
|
||||||
],
|
],
|
||||||
productivity: [
|
"productivity": [
|
||||||
"libreoffice",
|
"libreoffice",
|
||||||
"thunderbird",
|
"thunderbird",
|
||||||
|
"firefox-esr",
|
||||||
|
"chromium"
|
||||||
],
|
],
|
||||||
education: [
|
"education": [
|
||||||
"anki",
|
]
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
"arch": {
|
||||||
debian: {
|
"development": [
|
||||||
development: [
|
|
||||||
"git",
|
"git",
|
||||||
|
"base-devel",
|
||||||
"code",
|
"code",
|
||||||
"nodejs",
|
"nodejs",
|
||||||
"python3",
|
"npm",
|
||||||
"docker.io",
|
"python-pip",
|
||||||
"curl",
|
"jdk17-openjdk"
|
||||||
],
|
],
|
||||||
design: [
|
"design": [
|
||||||
"gimp",
|
"gimp",
|
||||||
"inkscape",
|
"inkscape",
|
||||||
"blender",
|
"blender",
|
||||||
|
"krita"
|
||||||
],
|
],
|
||||||
multimedia: [
|
"multimedia": [
|
||||||
"vlc",
|
"vlc",
|
||||||
"audacity",
|
"audacity",
|
||||||
"obs-studio",
|
"obs-studio",
|
||||||
|
"ffmpeg",
|
||||||
|
"mpv",
|
||||||
|
"handbrake"
|
||||||
],
|
],
|
||||||
"system-tools": [
|
"system-tools": [
|
||||||
"htop",
|
"htop",
|
||||||
"neofetch",
|
"fastfetch",
|
||||||
"tldr",
|
"tldr",
|
||||||
|
"tmux",
|
||||||
|
"zsh",
|
||||||
|
"gparted",
|
||||||
|
"timeshift",
|
||||||
|
"keepassxc",
|
||||||
|
"reflector",
|
||||||
|
"pacman-contrib"
|
||||||
],
|
],
|
||||||
gaming: [
|
"gaming": [
|
||||||
"steam",
|
"steam",
|
||||||
|
"lutris",
|
||||||
|
"gamemode",
|
||||||
|
"mangohud",
|
||||||
"discord",
|
"discord",
|
||||||
|
"wine",
|
||||||
|
"winetricks"
|
||||||
],
|
],
|
||||||
productivity: [
|
"productivity": [
|
||||||
"libreoffice",
|
|
||||||
"thunderbird",
|
|
||||||
],
|
|
||||||
education: [
|
|
||||||
"anki",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
arch: {
|
|
||||||
development: [
|
|
||||||
"git",
|
|
||||||
"visual-studio-code-bin",
|
|
||||||
"nodejs",
|
|
||||||
"python",
|
|
||||||
"docker",
|
|
||||||
"postman-bin",
|
|
||||||
],
|
|
||||||
design: [
|
|
||||||
"gimp",
|
|
||||||
"inkscape",
|
|
||||||
"blender",
|
|
||||||
],
|
|
||||||
multimedia: [
|
|
||||||
"vlc",
|
|
||||||
"audacity",
|
|
||||||
"obs-studio",
|
|
||||||
],
|
|
||||||
"system-tools": [
|
|
||||||
"htop",
|
|
||||||
"neofetch",
|
|
||||||
"tldr",
|
|
||||||
],
|
|
||||||
gaming: [
|
|
||||||
"steam",
|
|
||||||
"discord",
|
|
||||||
],
|
|
||||||
productivity: [
|
|
||||||
"libreoffice-fresh",
|
"libreoffice-fresh",
|
||||||
"thunderbird",
|
"thunderbird",
|
||||||
|
"firefox",
|
||||||
|
"chromium",
|
||||||
|
"obsidian"
|
||||||
],
|
],
|
||||||
education: [
|
"education": [
|
||||||
"anki",
|
"anki"
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
|
"fedora": {
|
||||||
fedora: {
|
"development": [
|
||||||
development: [
|
|
||||||
"git",
|
"git",
|
||||||
"code",
|
"curl",
|
||||||
"nodejs",
|
"nodejs",
|
||||||
"python3",
|
"python3",
|
||||||
"docker",
|
"python3-pip",
|
||||||
"curl",
|
"java-17-openjdk-devel",
|
||||||
|
"dotnet-sdk-8.0"
|
||||||
],
|
],
|
||||||
design: [
|
"design": [
|
||||||
"gimp",
|
"gimp",
|
||||||
"inkscape",
|
"inkscape",
|
||||||
"blender",
|
"blender",
|
||||||
|
"krita"
|
||||||
],
|
],
|
||||||
multimedia: [
|
"multimedia": [
|
||||||
"vlc",
|
"vlc",
|
||||||
"audacity",
|
"audacity",
|
||||||
"obs-studio",
|
"obs-studio",
|
||||||
|
"mpv"
|
||||||
],
|
],
|
||||||
"system-tools": [
|
"system-tools": [
|
||||||
"htop",
|
"htop",
|
||||||
"neofetch",
|
"fastfetch",
|
||||||
"tldr",
|
"tldr",
|
||||||
|
"tmux",
|
||||||
|
"zsh",
|
||||||
|
"gparted",
|
||||||
|
"keepassxc",
|
||||||
|
"dnf-plugins-core"
|
||||||
],
|
],
|
||||||
gaming: [
|
"gaming": [
|
||||||
"steam",
|
"lutris",
|
||||||
"discord",
|
"gamemode",
|
||||||
|
"mangohud"
|
||||||
],
|
],
|
||||||
productivity: [
|
"productivity": [
|
||||||
"libreoffice",
|
"libreoffice",
|
||||||
"thunderbird",
|
"thunderbird",
|
||||||
|
"firefox",
|
||||||
|
"chromium"
|
||||||
],
|
],
|
||||||
education: [
|
"education": []
|
||||||
"anki",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -252,3 +399,202 @@ export function getPackagesForPlatform(
|
|||||||
|
|
||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get package names with their categories for a specific platform
|
||||||
|
*/
|
||||||
|
export function getPackagesWithCategories(
|
||||||
|
platformId: string,
|
||||||
|
categories: UserCategory[]
|
||||||
|
): { name: string; category: UserCategory }[] {
|
||||||
|
const platform = PACKAGE_PRESETS[platformId as PlatformId];
|
||||||
|
if (!platform) return [];
|
||||||
|
|
||||||
|
const packages: { name: string; category: UserCategory }[] = [];
|
||||||
|
categories.forEach((category) => {
|
||||||
|
const categoryPackages = platform[category] || [];
|
||||||
|
categoryPackages.forEach((name) => {
|
||||||
|
packages.push({ name, category });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PRESET_DESCRIPTIONS: Record<string, string> = {
|
||||||
|
// Development
|
||||||
|
"git": "Distributed version control system",
|
||||||
|
"Git.Git": "Distributed version control system",
|
||||||
|
"curl": "Command line tool for transferring data with URLs",
|
||||||
|
"wget": "Network utility to retrieve files from the Web",
|
||||||
|
"nodejs": "JavaScript runtime built on Chrome's V8 JavaScript engine",
|
||||||
|
"npm": "Package manager for the Node.js JavaScript platform",
|
||||||
|
"python3": "Interpreted, interactive, object-oriented programming language",
|
||||||
|
"python3-pip": "Python package installer",
|
||||||
|
"python-pip": "Python package installer",
|
||||||
|
"docker.io": "Linux container runtime",
|
||||||
|
"Docker.DockerDesktop": "Build, Share, and Run container applications",
|
||||||
|
"dotnet-sdk-8.0": ".NET 8.0 Software Development Kit",
|
||||||
|
"dotnet-sdk": ".NET Software Development Kit",
|
||||||
|
"Microsoft.VisualStudioCode": "Code editing. Redefined.",
|
||||||
|
"visual-studio-code": "Code editing. Redefined.",
|
||||||
|
"code": "The Open Source build of Visual Studio Code",
|
||||||
|
"Postman.Postman": "Platform for building and using APIs",
|
||||||
|
"postman": "Platform for building and using APIs",
|
||||||
|
"Microsoft.WindowsTerminal": "Modern terminal application for Windows",
|
||||||
|
"iterm2": "Terminal emulator for macOS",
|
||||||
|
"warp": "AI-powered terminal",
|
||||||
|
"sublime-text": "Sophisticated text editor for code, markup and prose",
|
||||||
|
"build-essential": "Informational list of build-essential packages",
|
||||||
|
"base-devel": "Basic tools to build Arch Linux packages",
|
||||||
|
"java-17-openjdk-devel": "OpenJDK 17 Development Kit",
|
||||||
|
"jdk17-openjdk": "OpenJDK 17 Development Kit",
|
||||||
|
"temurin": "Eclipse Temurin Java SE binaries",
|
||||||
|
|
||||||
|
// Design
|
||||||
|
"gimp": "GNU Image Manipulation Program",
|
||||||
|
"GIMP.GIMP": "GNU Image Manipulation Program",
|
||||||
|
"inkscape": "Vector-based drawing program",
|
||||||
|
"Inkscape.Inkscape": "Vector-based drawing program",
|
||||||
|
"blender": "Very fast and versatile 3D modeller/renderer",
|
||||||
|
"BlenderFoundation.Blender": "Very fast and versatile 3D modeller/renderer",
|
||||||
|
"krita": "Digital painting and sketching application",
|
||||||
|
"KDE.Krita": "Digital painting and sketching application",
|
||||||
|
"darktable": "Virtual lighttable and darkroom for photographers",
|
||||||
|
"xnviewmp": "Image viewer, browser and converter",
|
||||||
|
"XnSoft.XnViewMP": "Image viewer, browser and converter",
|
||||||
|
"IrfanSkiljan.IrfanView": "Fast and compact image viewer",
|
||||||
|
"FastStone.Viewer": "Image viewer, converter and editor",
|
||||||
|
"ShareX.ShareX": "Screen capture, file sharing and productivity tool",
|
||||||
|
"Greenshot.Greenshot": "Lightweight screenshot software tool",
|
||||||
|
|
||||||
|
// Multimedia
|
||||||
|
"vlc": "Multimedia player and streamer",
|
||||||
|
"VideoLAN.VLC": "Multimedia player and streamer",
|
||||||
|
"audacity": "Multi-track audio editor and recorder",
|
||||||
|
"Audacity.Audacity": "Multi-track audio editor and recorder",
|
||||||
|
"obs-studio": "Software for live streaming and screen recording",
|
||||||
|
"obs": "Software for live streaming and screen recording",
|
||||||
|
"OBSProject.OBSStudio": "Software for live streaming and screen recording",
|
||||||
|
"ffmpeg": "Tools for transcoding, streaming and playing of multimedia files",
|
||||||
|
"mpv": "Video player based on MPlayer/mplayer2",
|
||||||
|
"handbrake": "Open Source Video Transcoder",
|
||||||
|
"HandBrake.HandBrake": "Open Source Video Transcoder",
|
||||||
|
"kdenlive": "Non-linear video editor",
|
||||||
|
"spotify": "Music streaming service",
|
||||||
|
"Spotify.Spotify": "Music streaming service",
|
||||||
|
"Apple.iTunes": "Media player, media library, and mobile device management utility",
|
||||||
|
"foobar2000": "Advanced audio player",
|
||||||
|
"PeterPawlowski.foobar2000": "Advanced audio player",
|
||||||
|
"Winamp.Winamp": "Media player for Windows",
|
||||||
|
"AIMP.AIMP": "Free audio player",
|
||||||
|
"iina": "The modern video player for macOS",
|
||||||
|
|
||||||
|
// System Tools
|
||||||
|
"htop": "Interactive process viewer",
|
||||||
|
"fastfetch": "Like neofetch, but much faster",
|
||||||
|
"neofetch": "Command-line system information tool",
|
||||||
|
"tmux": "Terminal multiplexer",
|
||||||
|
"zsh": "Shell with lots of features",
|
||||||
|
"gparted": "GNOME Partition Editor",
|
||||||
|
"timeshift": "System restore utility",
|
||||||
|
"stacer": "Linux System Optimizer and Monitoring",
|
||||||
|
"keepassxc": "Cross Platform Password Manager",
|
||||||
|
"DominikReichl.KeePass": "Password manager",
|
||||||
|
"synaptic": "Graphical package manager",
|
||||||
|
"7zip.7zip": "File archiver with a high compression ratio",
|
||||||
|
"Microsoft.PowerToys": "Set of system utilities for power users",
|
||||||
|
"voidtools.Everything": "Locate files and folders by name instantly",
|
||||||
|
"RARLab.WinRAR": "Powerful archiver and archive manager",
|
||||||
|
"TeamViewer.TeamViewer": "Remote control and meeting software",
|
||||||
|
"teamviewer": "Remote control and meeting software",
|
||||||
|
"RealVNC.VNCViewer": "Remote control software",
|
||||||
|
"rufus": "Create bootable USB drives the easy way",
|
||||||
|
"Rufus.Rufus": "Create bootable USB drives the easy way",
|
||||||
|
"bleachbit": "Delete unnecessary files from the system",
|
||||||
|
"BleachBit.BleachBit": "Delete unnecessary files from the system",
|
||||||
|
"rectangle": "Move and resize windows in macOS using keyboard shortcuts",
|
||||||
|
"the-unarchiver": "Unpack any archive file",
|
||||||
|
"keka": "The macOS file archiver",
|
||||||
|
"appcleaner": "Uninstall unwanted apps",
|
||||||
|
"raycast": "Productivity tool that replaces Spotlight",
|
||||||
|
"alfred": "Productivity app for macOS",
|
||||||
|
"qbittorrent": "BitTorrent client",
|
||||||
|
"qBittorrent.qBittorrent": "BitTorrent client",
|
||||||
|
|
||||||
|
// Gaming
|
||||||
|
"steam": "Digital distribution platform for video games",
|
||||||
|
"Valve.Steam": "Digital distribution platform for video games",
|
||||||
|
"lutris": "Open Source gaming platform for Linux",
|
||||||
|
"gamemode": "Optimize Linux system performance for gaming",
|
||||||
|
"mangohud": "Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load",
|
||||||
|
"discord": "All-in-one voice and text chat for gamers",
|
||||||
|
"Discord.Discord": "All-in-one voice and text chat for gamers",
|
||||||
|
"wine": "Run Windows applications on Linux",
|
||||||
|
"winetricks": "Workarounds for problems in Wine",
|
||||||
|
"EpicGames.EpicGamesLauncher": "Epic Games Store",
|
||||||
|
"epic-games": "Epic Games Store",
|
||||||
|
"GOG.Galaxy": "GOG Galaxy Client",
|
||||||
|
|
||||||
|
// Productivity
|
||||||
|
"libreoffice": "Office productivity suite",
|
||||||
|
"TheDocumentFoundation.LibreOffice": "Office productivity suite",
|
||||||
|
"libreoffice-fresh": "Office productivity suite (fresh version)",
|
||||||
|
"thunderbird": "Email, newsgroup and chat client",
|
||||||
|
"Mozilla.Thunderbird": "Email, newsgroup and chat client",
|
||||||
|
"firefox": "Mozilla Firefox web browser",
|
||||||
|
"Mozilla.Firefox": "Mozilla Firefox web browser",
|
||||||
|
"chromium": "Web browser",
|
||||||
|
"chromium-browser": "Web browser",
|
||||||
|
"Google.Chrome": "Web browser",
|
||||||
|
"google-chrome": "Web browser",
|
||||||
|
"Microsoft.Edge": "Web browser",
|
||||||
|
"microsoft-edge": "Web browser",
|
||||||
|
"Brave.Brave": "Secure, fast, and private web browser",
|
||||||
|
"brave-browser": "Secure, fast, and private web browser",
|
||||||
|
"Opera.Opera": "Web browser",
|
||||||
|
"opera": "Web browser",
|
||||||
|
"zoom": "Video conferencing",
|
||||||
|
"Zoom.Zoom": "Video conferencing",
|
||||||
|
"microsoft-teams": "Communication and collaboration platform",
|
||||||
|
"Microsoft.Teams": "Communication and collaboration platform",
|
||||||
|
"slack": "Collaboration hub for work",
|
||||||
|
"SlackTechnologies.Slack": "Collaboration hub for work",
|
||||||
|
"notion": "All-in-one workspace",
|
||||||
|
"Notion.Notion": "All-in-one workspace",
|
||||||
|
"obsidian": "Knowledge base that works on local Markdown files",
|
||||||
|
"Obsidian.Obsidian": "Knowledge base that works on local Markdown files",
|
||||||
|
"foxitreader": "PDF Reader",
|
||||||
|
"Foxit.FoxitReader": "PDF Reader",
|
||||||
|
"adobe-acrobat-reader": "PDF Reader",
|
||||||
|
"dropbox": "File hosting service",
|
||||||
|
"Dropbox.Dropbox": "File hosting service",
|
||||||
|
"onedrive": "File hosting service",
|
||||||
|
"Microsoft.OneDrive": "File hosting service",
|
||||||
|
"google-drive": "File hosting service",
|
||||||
|
"evernote": "Note taking app",
|
||||||
|
"Evernote.Evernote": "Note taking app",
|
||||||
|
"evolution": "Groupware suite",
|
||||||
|
"focuswriter": "Distraction-free word processor",
|
||||||
|
|
||||||
|
// Education
|
||||||
|
"anki": "Powerful, intelligent flash cards",
|
||||||
|
"Anki.Anki": "Powerful, intelligent flash cards",
|
||||||
|
"zotero": "Your personal research assistant"
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getPresetDetails(name: string): { description: string } {
|
||||||
|
// Try exact match
|
||||||
|
if (PRESET_DESCRIPTIONS[name]) {
|
||||||
|
return { description: PRESET_DESCRIPTIONS[name] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try case insensitive
|
||||||
|
const lowerName = name.toLowerCase();
|
||||||
|
const key = Object.keys(PRESET_DESCRIPTIONS).find(k => k.toLowerCase() === lowerName);
|
||||||
|
if (key) {
|
||||||
|
return { description: PRESET_DESCRIPTIONS[key] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { description: "Recommended package" };
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,8 +16,16 @@ export async function middleware(request: NextRequest) {
|
|||||||
request.ip ||
|
request.ip ||
|
||||||
'CACHE_TOKEN'
|
'CACHE_TOKEN'
|
||||||
|
|
||||||
|
// Exempt localhost from rate limiting
|
||||||
|
const isLocalhost = ip === '127.0.0.1' ||
|
||||||
|
ip === '::1' ||
|
||||||
|
ip === 'localhost' ||
|
||||||
|
ip === 'CACHE_TOKEN'
|
||||||
|
|
||||||
|
if (!isLocalhost) {
|
||||||
// 50 requests per minute per IP
|
// 50 requests per minute per IP
|
||||||
await limiter.check(null, 50, ip)
|
await limiter.check(null, 50, ip)
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: 'Too Many Requests' },
|
{ error: 'Too Many Requests' },
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import { PackageService } from "./packageService";
|
|
||||||
import { Package } from "@/models/Package";
|
import { Package } from "@/models/Package";
|
||||||
import {
|
import {
|
||||||
RecommendationRequest,
|
RecommendationRequest,
|
||||||
RecommendedPackage,
|
RecommendedPackage,
|
||||||
UserCategory,
|
UserCategory,
|
||||||
ExperienceLevel,
|
|
||||||
} from "@/types/recommendations";
|
} from "@/types/recommendations";
|
||||||
import { getPackagesForPlatform } from "@/data/recommendationPresets";
|
import { getPackagesWithCategories, getPresetDetails } from "@/data/recommendationPresets";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class RecommendationService {
|
export class RecommendationService {
|
||||||
/**
|
/**
|
||||||
@@ -17,19 +13,19 @@ export class RecommendationService {
|
|||||||
static async generateRecommendations(
|
static async generateRecommendations(
|
||||||
request: RecommendationRequest
|
request: RecommendationRequest
|
||||||
): Promise<RecommendedPackage[]> {
|
): Promise<RecommendedPackage[]> {
|
||||||
const { platform_id, categories, experienceLevel, limit = 20 } = request;
|
const { platform_id, categories, limit = 20 } = request;
|
||||||
|
|
||||||
// Step 1: Get preset package names for the user's categories and platform
|
// Step 1: Get preset package names for the user's categories and platform
|
||||||
const presetPackageNames = getPackagesForPlatform(platform_id, categories);
|
const presetPackagesInfo = getPackagesWithCategories(platform_id, categories);
|
||||||
|
const presetPackageNames = presetPackagesInfo.map(p => p.name);
|
||||||
|
|
||||||
// Step 2: Fetch packages from database
|
// Step 2: Generate packages from presets (no DB query)
|
||||||
const packageCategoryMap = new Map<string, UserCategory>();
|
const packageCategoryMap = new Map<string, UserCategory>();
|
||||||
|
|
||||||
// Fetch preset packages
|
// Fetch preset packages
|
||||||
const presetPackages = await this.fetchPresetPackages(
|
const presetPackages = await this.fetchPresetPackages(
|
||||||
presetPackageNames,
|
presetPackagesInfo,
|
||||||
platform_id,
|
platform_id,
|
||||||
categories,
|
|
||||||
packageCategoryMap
|
packageCategoryMap
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -55,54 +51,49 @@ export class RecommendationService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch packages that match preset names
|
* Fetch packages that match preset names
|
||||||
|
* optimized to use static data instead of DB queries
|
||||||
*/
|
*/
|
||||||
private static async fetchPresetPackages(
|
private static async fetchPresetPackages(
|
||||||
packageNames: string[],
|
packagesInfo: { name: string; category: UserCategory }[],
|
||||||
platformId: string,
|
platformId: string,
|
||||||
categories: UserCategory[],
|
|
||||||
categoryMap: Map<string, UserCategory>
|
categoryMap: Map<string, UserCategory>
|
||||||
): Promise<Package[]> {
|
): Promise<Package[]> {
|
||||||
if (packageNames.length === 0) {
|
if (packagesInfo.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const packages: Package[] = [];
|
const packages: Package[] = [];
|
||||||
let categoryIndex = 0;
|
|
||||||
|
|
||||||
// Search for each package name (case-insensitive)
|
for (const { name, category } of packagesInfo) {
|
||||||
for (const name of packageNames) {
|
const { description } = getPresetDetails(name);
|
||||||
const result = await PackageService.getMany({
|
|
||||||
|
// Create a mock package object to avoid database queries
|
||||||
|
// This ensures instant loading for recommendations
|
||||||
|
const mockPackage: Package = {
|
||||||
|
id: `${platformId}:${name.toLowerCase()}`,
|
||||||
|
name: name,
|
||||||
|
description: description,
|
||||||
|
version: "latest",
|
||||||
platform_id: platformId,
|
platform_id: platformId,
|
||||||
search: name,
|
type: "cli",
|
||||||
limit: 5, // Get top 5 matches to handle variations
|
repository: "official",
|
||||||
sort_by: "popularity_score",
|
popularity_score: 100,
|
||||||
sort_order: "desc",
|
is_active: true,
|
||||||
});
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
// Find best match (case-insensitive, exact name preferred)
|
downloads_count: 10000,
|
||||||
const exactMatch = result.packages.find(
|
platform: {
|
||||||
(pkg) => pkg.name.toLowerCase() === name.toLowerCase()
|
id: platformId,
|
||||||
);
|
name: platformId.charAt(0).toUpperCase() + platformId.slice(1),
|
||||||
|
package_manager: "unknown"
|
||||||
if (exactMatch) {
|
|
||||||
packages.push(exactMatch);
|
|
||||||
// Distribute categories evenly
|
|
||||||
categoryMap.set(exactMatch.id, categories[categoryIndex % categories.length]);
|
|
||||||
categoryIndex++;
|
|
||||||
} else if (result.packages.length > 0) {
|
|
||||||
// If no exact match, take the first result (most popular match)
|
|
||||||
packages.push(result.packages[0]);
|
|
||||||
categoryMap.set(result.packages[0].id, categories[categoryIndex % categories.length]);
|
|
||||||
categoryIndex++;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.push(mockPackage);
|
||||||
|
categoryMap.set(mockPackage.id, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
return packages;
|
return packages;
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching preset packages:", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user