mirror of
https://github.com/samanhappy/mcphub.git
synced 2025-12-24 18:59:30 -05:00
Compare commits
5 Commits
v0.10.2
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a9ea9bc4b | ||
|
|
3acdd99664 | ||
|
|
4ac875860c | ||
|
|
7b9e9da7bc | ||
|
|
cd7e2a23a3 |
28
README.md
28
README.md
@@ -98,6 +98,34 @@ Manual registration example:
|
||||
|
||||
For manual providers, create the OAuth App in the upstream console, set the redirect URI to `http://localhost:3000/oauth/callback` (or your deployed domain), and then plug the credentials into the dashboard or config file.
|
||||
|
||||
#### Connection Modes (Optional)
|
||||
|
||||
MCPHub supports two connection strategies:
|
||||
|
||||
- **`persistent` (default)**: Maintains long-running connections for stateful servers
|
||||
- **`on-demand`**: Connects only when needed, ideal for ephemeral servers that exit after operations
|
||||
|
||||
Example for one-time use servers:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"pdf-reader": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "pdf-mcp-server"],
|
||||
"connectionMode": "on-demand"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `on-demand` mode for servers that:
|
||||
- Don't support long-running connections
|
||||
- Exit automatically after handling requests
|
||||
- Experience "Connection closed" errors
|
||||
|
||||
See the [Configuration Guide](docs/configuration/mcp-settings.mdx) for more details.
|
||||
|
||||
### Docker Deployment
|
||||
|
||||
**Recommended**: Mount your custom config:
|
||||
|
||||
@@ -72,9 +72,13 @@ MCPHub uses several configuration files:
|
||||
|
||||
### Optional Fields
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
| -------------- | ------- | --------------- | --------------------------- |
|
||||
| `env` | object | `{}` | Environment variables |
|
||||
| Field | Type | Default | Description |
|
||||
| ---------------- | ------- | --------------- | --------------------------------------------------------------------- |
|
||||
| `env` | object | `{}` | Environment variables |
|
||||
| `connectionMode` | string | `"persistent"` | Connection strategy: `"persistent"` or `"on-demand"` |
|
||||
| `enabled` | boolean | `true` | Enable/disable the server |
|
||||
| `keepAliveInterval` | number | `60000` | Keep-alive ping interval for SSE connections (milliseconds) |
|
||||
| `options` | object | `{}` | MCP request options (timeout, resetTimeoutOnProgress, maxTotalTimeout)|
|
||||
|
||||
## Common MCP Server Examples
|
||||
|
||||
@@ -238,6 +242,68 @@ MCPHub uses several configuration files:
|
||||
}
|
||||
```
|
||||
|
||||
## Connection Modes
|
||||
|
||||
MCPHub supports two connection strategies for MCP servers:
|
||||
|
||||
### Persistent Connection (Default)
|
||||
|
||||
Persistent mode maintains a long-running connection to the MCP server. This is the default and recommended mode for most servers.
|
||||
|
||||
**Use cases:**
|
||||
- Servers that maintain state between requests
|
||||
- Servers with slow startup times
|
||||
- Servers designed for long-running connections
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"github": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-github"],
|
||||
"connectionMode": "persistent",
|
||||
"env": {
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### On-Demand Connection
|
||||
|
||||
On-demand mode connects only when a tool is invoked, then disconnects immediately after. This is ideal for servers that:
|
||||
- Don't support long-running connections
|
||||
- Are designed for one-time use
|
||||
- Exit automatically after handling requests
|
||||
|
||||
**Use cases:**
|
||||
- PDF processing tools that exit after each operation
|
||||
- One-time command-line utilities
|
||||
- Servers with connection stability issues
|
||||
- Resource-intensive servers that shouldn't run continuously
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"pdf-reader": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "pdf-mcp-server"],
|
||||
"connectionMode": "on-demand",
|
||||
"env": {
|
||||
"PDF_CACHE_DIR": "/tmp/pdf-cache"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits of on-demand mode:**
|
||||
- Avoids "Connection closed" errors for ephemeral services
|
||||
- Reduces resource usage for infrequently used tools
|
||||
- Better suited for stateless operations
|
||||
- Handles servers that automatically exit after operations
|
||||
|
||||
**Note:** On-demand servers briefly connect during initialization to discover available tools, then disconnect. The connection is re-established only when a tool from that server is actually invoked.
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Environment Variable Substitution
|
||||
|
||||
61
examples/mcp_settings_with_connection_modes.json
Normal file
61
examples/mcp_settings_with_connection_modes.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft-07/schema",
|
||||
"description": "Example MCP settings showing different connection modes",
|
||||
"mcpServers": {
|
||||
"github": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-github"],
|
||||
"connectionMode": "persistent",
|
||||
"env": {
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"playwright": {
|
||||
"command": "npx",
|
||||
"args": ["@playwright/mcp@latest", "--headless"],
|
||||
"connectionMode": "persistent",
|
||||
"enabled": true
|
||||
},
|
||||
"pdf-reader": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "pdf-mcp-server"],
|
||||
"connectionMode": "on-demand",
|
||||
"env": {
|
||||
"PDF_CACHE_DIR": "/tmp/pdf-cache"
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"image-processor": {
|
||||
"command": "python",
|
||||
"args": ["-m", "image_mcp_server"],
|
||||
"connectionMode": "on-demand",
|
||||
"env": {
|
||||
"IMAGE_OUTPUT_DIR": "/tmp/images"
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"fetch": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-fetch"],
|
||||
"enabled": true
|
||||
},
|
||||
"slack": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-slack"],
|
||||
"connectionMode": "persistent",
|
||||
"env": {
|
||||
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
|
||||
"SLACK_TEAM_ID": "${SLACK_TEAM_ID}"
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "$2b$10$Vt7krIvjNgyN67LXqly0uOcTpN0LI55cYRbcKC71pUDAP0nJ7RPa.",
|
||||
"isAdmin": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,8 +11,7 @@ const LanguageSwitch: React.FC = () => {
|
||||
const availableLanguages = [
|
||||
{ code: 'en', label: 'English' },
|
||||
{ code: 'zh', label: '中文' },
|
||||
{ code: 'fr', label: 'Français' },
|
||||
{ code: 'tr', label: 'Türkçe' }
|
||||
{ code: 'fr', label: 'Français' }
|
||||
];
|
||||
|
||||
// Update current language when it changes
|
||||
|
||||
@@ -6,7 +6,6 @@ import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import enTranslation from '../../locales/en.json';
|
||||
import zhTranslation from '../../locales/zh.json';
|
||||
import frTranslation from '../../locales/fr.json';
|
||||
import trTranslation from '../../locales/tr.json';
|
||||
|
||||
i18n
|
||||
// Detect user language
|
||||
@@ -25,9 +24,6 @@ i18n
|
||||
fr: {
|
||||
translation: frTranslation,
|
||||
},
|
||||
tr: {
|
||||
translation: trTranslation,
|
||||
},
|
||||
},
|
||||
fallbackLng: 'en',
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
|
||||
747
locales/tr.json
747
locales/tr.json
@@ -1,747 +0,0 @@
|
||||
{
|
||||
"app": {
|
||||
"title": "MCPHub Kontrol Paneli",
|
||||
"error": "Hata",
|
||||
"closeButton": "Kapat",
|
||||
"noServers": "Kullanılabilir MCP sunucusu yok",
|
||||
"loading": "Yükleniyor...",
|
||||
"logout": "Çıkış Yap",
|
||||
"profile": "Profil",
|
||||
"changePassword": "Şifre Değiştir",
|
||||
"toggleSidebar": "Kenar Çubuğunu Aç/Kapat",
|
||||
"welcomeUser": "Hoş geldin, {{username}}",
|
||||
"name": "MCPHub"
|
||||
},
|
||||
"about": {
|
||||
"title": "Hakkında",
|
||||
"versionInfo": "MCPHub Sürümü: {{version}}",
|
||||
"newVersion": "Yeni sürüm mevcut!",
|
||||
"currentVersion": "Mevcut sürüm",
|
||||
"newVersionAvailable": "Yeni sürüm {{version}} mevcut",
|
||||
"viewOnGitHub": "GitHub'da Görüntüle",
|
||||
"checkForUpdates": "Güncellemeleri Kontrol Et",
|
||||
"checking": "Güncellemeler kontrol ediliyor..."
|
||||
},
|
||||
"profile": {
|
||||
"viewProfile": "Profili görüntüle",
|
||||
"userCenter": "Kullanıcı Merkezi"
|
||||
},
|
||||
"sponsor": {
|
||||
"label": "Sponsor",
|
||||
"title": "Projeyi Destekle",
|
||||
"rewardAlt": "Ödül QR Kodu",
|
||||
"supportMessage": "Bana bir kahve ısmarlayarak MCPHub'ın geliştirilmesini destekleyin!",
|
||||
"supportButton": "Ko-fi'de Destek Ol"
|
||||
},
|
||||
"wechat": {
|
||||
"label": "WeChat",
|
||||
"title": "WeChat ile Bağlan",
|
||||
"qrCodeAlt": "WeChat QR Kodu",
|
||||
"scanMessage": "WeChat'te bizimle bağlantı kurmak için bu QR kodunu tarayın"
|
||||
},
|
||||
"discord": {
|
||||
"label": "Discord",
|
||||
"title": "Discord sunucumuza katılın",
|
||||
"community": "Destek, tartışmalar ve güncellemeler için büyüyen Discord topluluğumuza katılın!"
|
||||
},
|
||||
"theme": {
|
||||
"title": "Tema",
|
||||
"light": "Açık",
|
||||
"dark": "Koyu",
|
||||
"system": "Sistem"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Giriş Yap",
|
||||
"loginTitle": "MCPHub'a Giriş Yap",
|
||||
"slogan": "Birleşik MCP sunucu yönetim platformu",
|
||||
"subtitle": "Model Context Protocol sunucuları için merkezi yönetim platformu. Esnek yönlendirme stratejileri ile birden fazla MCP sunucusunu organize edin, izleyin ve ölçeklendirin.",
|
||||
"username": "Kullanıcı Adı",
|
||||
"password": "Şifre",
|
||||
"loggingIn": "Giriş yapılıyor...",
|
||||
"emptyFields": "Kullanıcı adı ve şifre boş olamaz",
|
||||
"loginFailed": "Giriş başarısız, lütfen kullanıcı adınızı ve şifrenizi kontrol edin",
|
||||
"loginError": "Giriş sırasında bir hata oluştu",
|
||||
"currentPassword": "Mevcut Şifre",
|
||||
"newPassword": "Yeni Şifre",
|
||||
"confirmPassword": "Şifreyi Onayla",
|
||||
"passwordsNotMatch": "Yeni şifre ve onay eşleşmiyor",
|
||||
"changePasswordSuccess": "Şifre başarıyla değiştirildi",
|
||||
"changePasswordError": "Şifre değişikliği başarısız oldu",
|
||||
"changePassword": "Şifre Değiştir",
|
||||
"passwordChanged": "Şifre başarıyla değiştirildi",
|
||||
"passwordChangeError": "Şifre değişikliği başarısız oldu",
|
||||
"defaultPasswordWarning": "Varsayılan Şifre Güvenlik Uyarısı",
|
||||
"defaultPasswordMessage": "Varsayılan şifreyi (admin123) kullanıyorsunuz, bu bir güvenlik riski oluşturur. Hesabınızı korumak için lütfen şifrenizi hemen değiştirin.",
|
||||
"goToSettings": "Ayarlara Git",
|
||||
"passwordStrengthError": "Şifre güvenlik gereksinimlerini karşılamıyor",
|
||||
"passwordMinLength": "Şifre en az 8 karakter uzunluğunda olmalıdır",
|
||||
"passwordRequireLetter": "Şifre en az bir harf içermelidir",
|
||||
"passwordRequireNumber": "Şifre en az bir rakam içermelidir",
|
||||
"passwordRequireSpecial": "Şifre en az bir özel karakter içermelidir",
|
||||
"passwordStrengthHint": "Şifre en az 8 karakter olmalı ve harf, rakam ve özel karakter içermelidir"
|
||||
},
|
||||
"server": {
|
||||
"addServer": "Sunucu Ekle",
|
||||
"add": "Ekle",
|
||||
"edit": "Düzenle",
|
||||
"copy": "Kopyala",
|
||||
"delete": "Sil",
|
||||
"confirmDelete": "Bu sunucuyu silmek istediğinizden emin misiniz?",
|
||||
"deleteWarning": "'{{name}}' sunucusunu silmek, onu ve tüm verilerini kaldıracaktır. Bu işlem geri alınamaz.",
|
||||
"status": "Durum",
|
||||
"tools": "Araçlar",
|
||||
"prompts": "İstekler",
|
||||
"name": "Sunucu Adı",
|
||||
"url": "Sunucu URL'si",
|
||||
"apiKey": "API Anahtarı",
|
||||
"save": "Kaydet",
|
||||
"cancel": "İptal",
|
||||
"invalidConfig": "{{serverName}} için yapılandırma verisi bulunamadı",
|
||||
"addError": "Sunucu eklenemedi",
|
||||
"editError": "{{serverName}} sunucusu düzenlenemedi",
|
||||
"deleteError": "{{serverName}} sunucusu silinemedi",
|
||||
"updateError": "Sunucu güncellenemedi",
|
||||
"editTitle": "Sunucuyu Düzenle: {{serverName}}",
|
||||
"type": "Sunucu Türü",
|
||||
"typeStdio": "STDIO",
|
||||
"typeSse": "SSE",
|
||||
"typeStreamableHttp": "Akış Yapılabilir HTTP",
|
||||
"typeOpenapi": "OpenAPI",
|
||||
"command": "Komut",
|
||||
"arguments": "Argümanlar",
|
||||
"envVars": "Ortam Değişkenleri",
|
||||
"headers": "HTTP Başlıkları",
|
||||
"key": "anahtar",
|
||||
"value": "değer",
|
||||
"enabled": "Etkin",
|
||||
"enable": "Etkinleştir",
|
||||
"disable": "Devre Dışı Bırak",
|
||||
"requestOptions": "Bağlantı Yapılandırması",
|
||||
"timeout": "İstek Zaman Aşımı",
|
||||
"timeoutDescription": "MCP sunucusuna yapılan istekler için zaman aşımı (ms)",
|
||||
"maxTotalTimeout": "Maksimum Toplam Zaman Aşımı",
|
||||
"maxTotalTimeoutDescription": "MCP sunucusuna gönderilen istekler için maksimum toplam zaman aşımı (ms) (İlerleme bildirimleriyle kullanın)",
|
||||
"resetTimeoutOnProgress": "İlerlemede Zaman Aşımını Sıfırla",
|
||||
"resetTimeoutOnProgressDescription": "İlerleme bildirimlerinde zaman aşımını sıfırla",
|
||||
"remove": "Kaldır",
|
||||
"toggleError": "{{serverName}} sunucusu açılamadı/kapatılamadı",
|
||||
"alreadyExists": "{{serverName}} sunucusu zaten mevcut",
|
||||
"invalidData": "Geçersiz sunucu verisi sağlandı",
|
||||
"notFound": "{{serverName}} sunucusu bulunamadı",
|
||||
"namePlaceholder": "Sunucu adını girin",
|
||||
"urlPlaceholder": "Sunucu URL'sini girin",
|
||||
"commandPlaceholder": "Komutu girin",
|
||||
"argumentsPlaceholder": "Argümanları girin",
|
||||
"errorDetails": "Hata Detayları",
|
||||
"viewErrorDetails": "Hata detaylarını görüntüle",
|
||||
"copyConfig": "Yapılandırmayı Kopyala",
|
||||
"confirmVariables": "Değişken Yapılandırmasını Onayla",
|
||||
"variablesDetected": "Yapılandırmada değişkenler algılandı. Lütfen bu değişkenlerin düzgün yapılandırıldığını onaylayın:",
|
||||
"detectedVariables": "Algılanan Değişkenler",
|
||||
"confirmVariablesMessage": "Lütfen bu değişkenlerin çalışma ortamınızda düzgün tanımlandığından emin olun. Sunucu eklemeye devam edilsin mi?",
|
||||
"confirmAndAdd": "Onayla ve Ekle",
|
||||
"openapi": {
|
||||
"inputMode": "Giriş Modu",
|
||||
"inputModeUrl": "Şartname URL'si",
|
||||
"inputModeSchema": "JSON Şeması",
|
||||
"specUrl": "OpenAPI Şartname URL'si",
|
||||
"schema": "OpenAPI JSON Şeması",
|
||||
"schemaHelp": "Eksiksiz OpenAPI JSON şemanızı buraya yapıştırın",
|
||||
"security": "Güvenlik Türü",
|
||||
"securityNone": "Yok",
|
||||
"securityApiKey": "API Anahtarı",
|
||||
"securityHttp": "HTTP Kimlik Doğrulaması",
|
||||
"securityOAuth2": "OAuth 2.0",
|
||||
"securityOpenIdConnect": "OpenID Connect",
|
||||
"apiKeyConfig": "API Anahtarı Yapılandırması",
|
||||
"apiKeyName": "Başlık/Parametre Adı",
|
||||
"apiKeyIn": "Konum",
|
||||
"apiKeyValue": "API Anahtarı Değeri",
|
||||
"httpAuthConfig": "HTTP Kimlik Doğrulama Yapılandırması",
|
||||
"httpScheme": "Kimlik Doğrulama Şeması",
|
||||
"httpCredentials": "Kimlik Bilgileri",
|
||||
"httpSchemeBasic": "Basit",
|
||||
"httpSchemeBearer": "Bearer",
|
||||
"httpSchemeDigest": "Digest",
|
||||
"oauth2Config": "OAuth 2.0 Yapılandırması",
|
||||
"oauth2Token": "Erişim Anahtarı",
|
||||
"openIdConnectConfig": "OpenID Connect Yapılandırması",
|
||||
"openIdConnectUrl": "URL'yi Keşfet",
|
||||
"openIdConnectToken": "ID Token",
|
||||
"apiKeyInHeader": "Başlık",
|
||||
"apiKeyInQuery": "Sorgu",
|
||||
"apiKeyInCookie": "Çerez",
|
||||
"passthroughHeaders": "Geçiş Başlıkları",
|
||||
"passthroughHeadersHelp": "Araç çağrısı isteklerinden yukarı akış OpenAPI uç noktalarına geçirilecek başlık adlarının virgülle ayrılmış listesi (örn. Authorization, X-API-Key)"
|
||||
},
|
||||
"oauth": {
|
||||
"sectionTitle": "OAuth Yapılandırması",
|
||||
"sectionDescription": "OAuth korumalı sunucular için istemci kimlik bilgilerini yapılandırın (isteğe bağlı).",
|
||||
"clientId": "İstemci ID",
|
||||
"clientSecret": "İstemci Gizli Anahtarı",
|
||||
"authorizationEndpoint": "Yetkilendirme Uç Noktası",
|
||||
"tokenEndpoint": "Token Uç Noktası",
|
||||
"scopes": "Kapsamlar",
|
||||
"scopesPlaceholder": "scope1 scope2",
|
||||
"resource": "Kaynak / Hedef Kitle",
|
||||
"accessToken": "Erişim Tokeni",
|
||||
"refreshToken": "Yenileme Tokeni"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"online": "Çevrimiçi",
|
||||
"offline": "Çevrimdışı",
|
||||
"connecting": "Bağlanıyor",
|
||||
"oauthRequired": "OAuth Gerekli",
|
||||
"clickToAuthorize": "OAuth ile yetkilendirmek için tıklayın",
|
||||
"oauthWindowOpened": "OAuth yetkilendirme penceresi açıldı. Lütfen yetkilendirmeyi tamamlayın."
|
||||
},
|
||||
"errors": {
|
||||
"general": "Bir şeyler yanlış gitti",
|
||||
"network": "Ağ bağlantı hatası. Lütfen internet bağlantınızı kontrol edin",
|
||||
"serverConnection": "Sunucuya bağlanılamıyor. Lütfen sunucunun çalışıp çalışmadığını kontrol edin",
|
||||
"serverAdd": "Sunucu eklenemedi. Lütfen sunucu durumunu kontrol edin",
|
||||
"serverUpdate": "{{serverName}} sunucusu düzenlenemedi. Lütfen sunucu durumunu kontrol edin",
|
||||
"serverFetch": "Sunucu verileri alınamadı. Lütfen daha sonra tekrar deneyin",
|
||||
"initialStartup": "Sunucu başlatılıyor olabilir. İlk başlatmada bu işlem biraz zaman alabileceğinden lütfen bekleyin...",
|
||||
"serverInstall": "Sunucu yüklenemedi",
|
||||
"failedToFetchSettings": "Ayarlar getirilemedi",
|
||||
"failedToUpdateRouteConfig": "Route yapılandırması güncellenemedi",
|
||||
"failedToUpdateSmartRoutingConfig": "Akıllı yönlendirme yapılandırması güncellenemedi"
|
||||
},
|
||||
"common": {
|
||||
"processing": "İşleniyor...",
|
||||
"save": "Kaydet",
|
||||
"cancel": "İptal",
|
||||
"back": "Geri",
|
||||
"refresh": "Yenile",
|
||||
"create": "Oluştur",
|
||||
"creating": "Oluşturuluyor...",
|
||||
"update": "Güncelle",
|
||||
"updating": "Güncelleniyor...",
|
||||
"submitting": "Gönderiliyor...",
|
||||
"delete": "Sil",
|
||||
"remove": "Kaldır",
|
||||
"copy": "Kopyala",
|
||||
"copyId": "ID'yi Kopyala",
|
||||
"copyUrl": "URL'yi Kopyala",
|
||||
"copyJson": "JSON'u Kopyala",
|
||||
"copySuccess": "Panoya kopyalandı",
|
||||
"copyFailed": "Kopyalama başarısız",
|
||||
"copied": "Kopyalandı",
|
||||
"close": "Kapat",
|
||||
"confirm": "Onayla",
|
||||
"language": "Dil",
|
||||
"true": "Doğru",
|
||||
"false": "Yanlış",
|
||||
"dismiss": "Anımsatma",
|
||||
"github": "GitHub",
|
||||
"wechat": "WeChat",
|
||||
"discord": "Discord",
|
||||
"required": "Gerekli",
|
||||
"secret": "Gizli",
|
||||
"default": "Varsayılan",
|
||||
"value": "Değer",
|
||||
"type": "Tür",
|
||||
"repeated": "Tekrarlanan",
|
||||
"valueHint": "Değer İpucu",
|
||||
"choices": "Seçenekler"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Kontrol Paneli",
|
||||
"servers": "Sunucular",
|
||||
"groups": "Gruplar",
|
||||
"users": "Kullanıcılar",
|
||||
"settings": "Ayarlar",
|
||||
"changePassword": "Şifre Değiştir",
|
||||
"market": "Market",
|
||||
"cloud": "Bulut Market",
|
||||
"logs": "Günlükler"
|
||||
},
|
||||
"pages": {
|
||||
"dashboard": {
|
||||
"title": "Kontrol Paneli",
|
||||
"totalServers": "Toplam",
|
||||
"onlineServers": "Çevrimiçi",
|
||||
"offlineServers": "Çevrimdışı",
|
||||
"connectingServers": "Bağlanıyor",
|
||||
"recentServers": "Son Sunucular"
|
||||
},
|
||||
"servers": {
|
||||
"title": "Sunucu Yönetimi"
|
||||
},
|
||||
"groups": {
|
||||
"title": "Grup Yönetimi"
|
||||
},
|
||||
"users": {
|
||||
"title": "Kullanıcı Yönetimi"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Ayarlar",
|
||||
"language": "Dil",
|
||||
"account": "Hesap Ayarları",
|
||||
"password": "Şifre Değiştir",
|
||||
"appearance": "Görünüm",
|
||||
"routeConfig": "Güvenlik",
|
||||
"installConfig": "Kurulum",
|
||||
"smartRouting": "Akıllı Yönlendirme"
|
||||
},
|
||||
"market": {
|
||||
"title": "Market Yönetimi - Yerel ve Bulut Marketler"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Sistem Günlükleri"
|
||||
}
|
||||
},
|
||||
"logs": {
|
||||
"filters": "Filtreler",
|
||||
"search": "Günlüklerde ara...",
|
||||
"autoScroll": "Otomatik kaydır",
|
||||
"clearLogs": "Günlükleri temizle",
|
||||
"loading": "Günlükler yükleniyor...",
|
||||
"noLogs": "Kullanılabilir günlük yok.",
|
||||
"noMatch": "Mevcut filtrelerle eşleşen günlük yok.",
|
||||
"mainProcess": "Ana İşlem",
|
||||
"childProcess": "Alt İşlem",
|
||||
"main": "Ana",
|
||||
"child": "Alt"
|
||||
},
|
||||
"groups": {
|
||||
"add": "Ekle",
|
||||
"addNew": "Yeni Grup Ekle",
|
||||
"edit": "Grubu Düzenle",
|
||||
"delete": "Sil",
|
||||
"confirmDelete": "Bu grubu silmek istediğinizden emin misiniz?",
|
||||
"deleteWarning": "'{{name}}' grubunu silmek, onu ve tüm sunucu ilişkilerini kaldıracaktır. Bu işlem geri alınamaz.",
|
||||
"name": "Grup Adı",
|
||||
"namePlaceholder": "Grup adını girin",
|
||||
"nameRequired": "Grup adı gereklidir",
|
||||
"description": "Açıklama",
|
||||
"descriptionPlaceholder": "Grup açıklamasını girin (isteğe bağlı)",
|
||||
"createError": "Grup oluşturulamadı",
|
||||
"updateError": "Grup güncellenemedi",
|
||||
"deleteError": "Grup silinemedi",
|
||||
"serverAddError": "Sunucu gruba eklenemedi",
|
||||
"serverRemoveError": "Sunucu gruptan kaldırılamadı",
|
||||
"addServer": "Gruba Sunucu Ekle",
|
||||
"selectServer": "Eklenecek bir sunucu seçin",
|
||||
"servers": "Gruptaki Sunucular",
|
||||
"remove": "Kaldır",
|
||||
"noGroups": "Kullanılabilir grup yok. Başlamak için yeni bir grup oluşturun.",
|
||||
"noServers": "Bu grupta sunucu yok.",
|
||||
"noServerOptions": "Kullanılabilir sunucu yok",
|
||||
"serverCount": "{{count}} Sunucu",
|
||||
"toolSelection": "Araç Seçimi",
|
||||
"toolsSelected": "Seçildi",
|
||||
"allTools": "Tümü",
|
||||
"selectedTools": "Seçili araçlar",
|
||||
"selectAll": "Tümünü Seç",
|
||||
"selectNone": "Hiçbirini Seçme",
|
||||
"configureTools": "Araçları Yapılandır"
|
||||
},
|
||||
"market": {
|
||||
"title": "Yerel Kurulum",
|
||||
"official": "Resmi",
|
||||
"by": "Geliştirici",
|
||||
"unknown": "Bilinmeyen",
|
||||
"tools": "araçlar",
|
||||
"search": "Ara",
|
||||
"searchPlaceholder": "Sunucuları isme, kategoriye veya etiketlere göre ara",
|
||||
"clearFilters": "Temizle",
|
||||
"clearCategoryFilter": "",
|
||||
"clearTagFilter": "",
|
||||
"categories": "Kategoriler",
|
||||
"tags": "Etiketler",
|
||||
"showTags": "Etiketleri göster",
|
||||
"hideTags": "Etiketleri gizle",
|
||||
"moreTags": "",
|
||||
"noServers": "Aramanızla eşleşen sunucu bulunamadı",
|
||||
"backToList": "Listeye dön",
|
||||
"install": "Yükle",
|
||||
"installing": "Yükleniyor...",
|
||||
"installed": "Yüklendi",
|
||||
"installServer": "Sunucu Yükle: {{name}}",
|
||||
"installSuccess": "{{serverName}} sunucusu başarıyla yüklendi",
|
||||
"author": "Yazar",
|
||||
"license": "Lisans",
|
||||
"repository": "Depo",
|
||||
"examples": "Örnekler",
|
||||
"arguments": "Argümanlar",
|
||||
"argumentName": "Ad",
|
||||
"description": "Açıklama",
|
||||
"required": "Gerekli",
|
||||
"example": "Örnek",
|
||||
"viewSchema": "Şemayı görüntüle",
|
||||
"fetchError": "Market sunucuları getirilirken hata",
|
||||
"serverNotFound": "Sunucu bulunamadı",
|
||||
"searchError": "Sunucular aranırken hata",
|
||||
"filterError": "Sunucular kategoriye göre filtrelenirken hata",
|
||||
"tagFilterError": "Sunucular etikete göre filtrelenirken hata",
|
||||
"noInstallationMethod": "Bu sunucu için kullanılabilir kurulum yöntemi yok",
|
||||
"showing": "{{total}} sunucudan {{from}}-{{to}} arası gösteriliyor",
|
||||
"perPage": "Sayfa başına",
|
||||
"confirmVariablesMessage": "Lütfen bu değişkenlerin çalışma ortamınızda düzgün tanımlandığından emin olun. Sunucu yüklemeye devam edilsin mi?",
|
||||
"confirmAndInstall": "Onayla ve Yükle"
|
||||
},
|
||||
"cloud": {
|
||||
"title": "Bulut Desteği",
|
||||
"subtitle": "MCPRouter tarafından desteklenmektedir",
|
||||
"by": "Geliştirici",
|
||||
"server": "Sunucu",
|
||||
"config": "Yapılandırma",
|
||||
"created": "Oluşturuldu",
|
||||
"updated": "Güncellendi",
|
||||
"available": "Kullanılabilir",
|
||||
"description": "Açıklama",
|
||||
"details": "Detaylar",
|
||||
"tools": "Araçlar",
|
||||
"tool": "araç",
|
||||
"toolsAvailable": "{{count}} araç mevcut",
|
||||
"loadingTools": "Araçlar yükleniyor...",
|
||||
"noTools": "Bu sunucu için kullanılabilir araç yok",
|
||||
"noDescription": "Kullanılabilir açıklama yok",
|
||||
"viewDetails": "Detayları Görüntüle",
|
||||
"parameters": "Parametreler",
|
||||
"result": "Sonuç",
|
||||
"error": "Hata",
|
||||
"callTool": "Çalıştır",
|
||||
"calling": "Çalıştırılıyor...",
|
||||
"toolCallSuccess": "{{toolName}} aracı başarıyla çalıştırıldı",
|
||||
"toolCallError": "{{toolName}} aracı çalıştırılamadı: {{error}}",
|
||||
"viewSchema": "Şemayı Görüntüle",
|
||||
"backToList": "Bulut Market'e Dön",
|
||||
"search": "Ara",
|
||||
"searchPlaceholder": "Bulut sunucularını isme, başlığa veya geliştiriciye göre ara",
|
||||
"clearFilters": "Filtreleri Temizle",
|
||||
"clearCategoryFilter": "Temizle",
|
||||
"clearTagFilter": "Temizle",
|
||||
"categories": "Kategoriler",
|
||||
"tags": "Etiketler",
|
||||
"noCategories": "Kategori bulunamadı",
|
||||
"noTags": "Etiket bulunamadı",
|
||||
"noServers": "Bulut sunucusu bulunamadı",
|
||||
"fetchError": "Bulut sunucuları getirilirken hata",
|
||||
"serverNotFound": "Bulut sunucusu bulunamadı",
|
||||
"searchError": "Bulut sunucuları aranırken hata",
|
||||
"filterError": "Bulut sunucuları kategoriye göre filtrelenirken hata",
|
||||
"tagFilterError": "Bulut sunucuları etikete göre filtrelenirken hata",
|
||||
"showing": "{{total}} bulut sunucusundan {{from}}-{{to}} arası gösteriliyor",
|
||||
"perPage": "Sayfa başına",
|
||||
"apiKeyNotConfigured": "MCPRouter API anahtarı yapılandırılmamış",
|
||||
"apiKeyNotConfiguredDescription": "Bulut sunucularını kullanmak için MCPRouter API anahtarınızı yapılandırmanız gerekir.",
|
||||
"getApiKey": "API Anahtarı Al",
|
||||
"configureInSettings": "Ayarlarda Yapılandır",
|
||||
"installServer": "{{name}} Yükle",
|
||||
"installSuccess": "{{name}} sunucusu başarıyla yüklendi",
|
||||
"installError": "Sunucu yüklenemedi: {{error}}"
|
||||
},
|
||||
"registry": {
|
||||
"title": "Kayıt",
|
||||
"official": "Resmi",
|
||||
"latest": "En Son",
|
||||
"description": "Açıklama",
|
||||
"website": "Web Sitesi",
|
||||
"repository": "Depo",
|
||||
"packages": "Paketler",
|
||||
"package": "paket",
|
||||
"remotes": "Uzak Sunucular",
|
||||
"remote": "uzak sunucu",
|
||||
"published": "Yayınlandı",
|
||||
"updated": "Güncellendi",
|
||||
"install": "Yükle",
|
||||
"installing": "Yükleniyor...",
|
||||
"installed": "Yüklendi",
|
||||
"installServer": "{{name}} Yükle",
|
||||
"installSuccess": "{{name}} sunucusu başarıyla yüklendi",
|
||||
"installError": "Sunucu yüklenemedi: {{error}}",
|
||||
"noDescription": "Kullanılabilir açıklama yok",
|
||||
"viewDetails": "Detayları Görüntüle",
|
||||
"backToList": "Kayda Dön",
|
||||
"search": "Ara",
|
||||
"searchPlaceholder": "Kayıt sunucularını isme göre ara",
|
||||
"clearFilters": "Temizle",
|
||||
"noServers": "Kayıt sunucusu bulunamadı",
|
||||
"fetchError": "Kayıt sunucuları getirilirken hata",
|
||||
"serverNotFound": "Kayıt sunucusu bulunamadı",
|
||||
"showing": "{{total}} kayıt sunucusundan {{from}}-{{to}} arası gösteriliyor",
|
||||
"perPage": "Sayfa başına",
|
||||
"environmentVariables": "Ortam Değişkenleri",
|
||||
"packageArguments": "Paket Argümanları",
|
||||
"runtimeArguments": "Çalışma Zamanı Argümanları",
|
||||
"headers": "Başlıklar"
|
||||
},
|
||||
"tool": {
|
||||
"run": "Çalıştır",
|
||||
"running": "Çalıştırılıyor...",
|
||||
"runTool": "Aracı Çalıştır",
|
||||
"cancel": "İptal",
|
||||
"noDescription": "Kullanılabilir açıklama yok",
|
||||
"inputSchema": "Giriş Şeması:",
|
||||
"runToolWithName": "Aracı Çalıştır: {{name}}",
|
||||
"execution": "Araç Çalıştırma",
|
||||
"successful": "Başarılı",
|
||||
"failed": "Başarısız",
|
||||
"result": "Sonuç:",
|
||||
"error": "Hata",
|
||||
"errorDetails": "Hata Detayları:",
|
||||
"noContent": "Araç başarıyla çalıştırıldı ancak içerik döndürmedi.",
|
||||
"unknownError": "Bilinmeyen hata oluştu",
|
||||
"jsonResponse": "JSON Yanıtı:",
|
||||
"toolResult": "Araç sonucu",
|
||||
"noParameters": "Bu araç herhangi bir parametre gerektirmez.",
|
||||
"selectOption": "Bir seçenek seçin",
|
||||
"enterValue": "{{type}} değeri girin",
|
||||
"enabled": "Etkin",
|
||||
"enableSuccess": "{{name}} aracı başarıyla etkinleştirildi",
|
||||
"disableSuccess": "{{name}} aracı başarıyla devre dışı bırakıldı",
|
||||
"toggleFailed": "Araç durumu değiştirilemedi",
|
||||
"parameters": "Araç Parametreleri",
|
||||
"formMode": "Form Modu",
|
||||
"jsonMode": "JSON Modu",
|
||||
"jsonConfiguration": "JSON Yapılandırması",
|
||||
"invalidJsonFormat": "Geçersiz JSON formatı",
|
||||
"fixJsonBeforeSwitching": "Form moduna geçmeden önce lütfen JSON formatını düzeltin",
|
||||
"item": "Öğe {{index}}",
|
||||
"addItem": "{{key}} öğesi ekle",
|
||||
"enterKey": "{{key}} girin"
|
||||
},
|
||||
"prompt": {
|
||||
"run": "Getir",
|
||||
"running": "Getiriliyor...",
|
||||
"result": "İstek Sonucu",
|
||||
"error": "İstek Hatası",
|
||||
"execution": "İstek Çalıştırma",
|
||||
"successful": "Başarılı",
|
||||
"failed": "Başarısız",
|
||||
"errorDetails": "Hata Detayları:",
|
||||
"noContent": "İstek başarıyla çalıştırıldı ancak içerik döndürmedi.",
|
||||
"unknownError": "Bilinmeyen hata oluştu",
|
||||
"jsonResponse": "JSON Yanıtı:",
|
||||
"description": "Açıklama",
|
||||
"messages": "Mesajlar",
|
||||
"noDescription": "Kullanılabilir açıklama yok",
|
||||
"runPromptWithName": "İsteği Getir: {{name}}"
|
||||
},
|
||||
"settings": {
|
||||
"enableGlobalRoute": "Global Yönlendirmeyi Etkinleştir",
|
||||
"enableGlobalRouteDescription": "Grup ID'si belirtmeden /sse uç noktasına bağlantıya izin ver",
|
||||
"enableGroupNameRoute": "Grup Adı Yönlendirmeyi Etkinleştir",
|
||||
"enableGroupNameRouteDescription": "Sadece grup ID'leri yerine grup adları kullanarak /sse uç noktasına bağlantıya izin ver",
|
||||
"enableBearerAuth": "Bearer Kimlik Doğrulamasını Etkinleştir",
|
||||
"enableBearerAuthDescription": "MCP istekleri için bearer token kimlik doğrulaması gerektir",
|
||||
"bearerAuthKey": "Bearer Kimlik Doğrulama Anahtarı",
|
||||
"bearerAuthKeyDescription": "Bearer token'da gerekli olacak kimlik doğrulama anahtarı",
|
||||
"bearerAuthKeyPlaceholder": "Bearer kimlik doğrulama anahtarını girin",
|
||||
"skipAuth": "Kimlik Doğrulamayı Atla",
|
||||
"skipAuthDescription": "Arayüz ve API erişimi için giriş gereksinimini atla (Güvenlik için VARSAYILAN KAPALI)",
|
||||
"pythonIndexUrl": "Python Paket Deposu URL'si",
|
||||
"pythonIndexUrlDescription": "Python paket kurulumu için UV_DEFAULT_INDEX ortam değişkenini ayarla",
|
||||
"pythonIndexUrlPlaceholder": "örn. https://pypi.org/simple",
|
||||
"npmRegistry": "NPM Kayıt URL'si",
|
||||
"npmRegistryDescription": "NPM paket kurulumu için npm_config_registry ortam değişkenini ayarla",
|
||||
"npmRegistryPlaceholder": "örn. https://registry.npmjs.org/",
|
||||
"baseUrl": "Temel URL",
|
||||
"baseUrlDescription": "MCP istekleri için temel URL",
|
||||
"baseUrlPlaceholder": "örn. http://localhost:3000",
|
||||
"installConfig": "Kurulum",
|
||||
"systemConfigUpdated": "Sistem yapılandırması başarıyla güncellendi",
|
||||
"enableSmartRouting": "Akıllı Yönlendirmeyi Etkinleştir",
|
||||
"enableSmartRoutingDescription": "Girdiye göre en uygun aracı aramak için akıllı yönlendirme özelliğini etkinleştir ($smart grup adını kullanarak)",
|
||||
"dbUrl": "PostgreSQL URL'si (pgvector desteği gerektirir)",
|
||||
"dbUrlPlaceholder": "örn. postgresql://kullanıcı:şifre@localhost:5432/veritabanıadı",
|
||||
"openaiApiBaseUrl": "OpenAI API Temel URL'si",
|
||||
"openaiApiBaseUrlPlaceholder": "https://api.openai.com/v1",
|
||||
"openaiApiKey": "OpenAI API Anahtarı",
|
||||
"openaiApiKeyPlaceholder": "OpenAI API anahtarını girin",
|
||||
"openaiApiEmbeddingModel": "OpenAI Entegrasyon Modeli",
|
||||
"openaiApiEmbeddingModelPlaceholder": "text-embedding-3-small",
|
||||
"smartRoutingConfigUpdated": "Akıllı yönlendirme yapılandırması başarıyla güncellendi",
|
||||
"smartRoutingRequiredFields": "Akıllı yönlendirmeyi etkinleştirmek için Veritabanı URL'si ve OpenAI API Anahtarı gereklidir",
|
||||
"smartRoutingValidationError": "Akıllı Yönlendirmeyi etkinleştirmeden önce lütfen gerekli alanları doldurun: {{fields}}",
|
||||
"mcpRouterConfig": "Bulut Market",
|
||||
"mcpRouterApiKey": "MCPRouter API Anahtarı",
|
||||
"mcpRouterApiKeyDescription": "MCPRouter bulut market hizmetlerine erişim için API anahtarı",
|
||||
"mcpRouterApiKeyPlaceholder": "MCPRouter API anahtarını girin",
|
||||
"mcpRouterReferer": "Yönlendiren",
|
||||
"mcpRouterRefererDescription": "MCPRouter API istekleri için Referer başlığı",
|
||||
"mcpRouterRefererPlaceholder": "https://www.mcphubx.com",
|
||||
"mcpRouterTitle": "Başlık",
|
||||
"mcpRouterTitleDescription": "MCPRouter API istekleri için Başlık başlığı",
|
||||
"mcpRouterTitlePlaceholder": "MCPHub",
|
||||
"mcpRouterBaseUrl": "Temel URL",
|
||||
"mcpRouterBaseUrlDescription": "MCPRouter API için temel URL",
|
||||
"mcpRouterBaseUrlPlaceholder": "https://api.mcprouter.to/v1",
|
||||
"systemSettings": "Sistem Ayarları",
|
||||
"nameSeparatorLabel": "İsim Ayırıcı",
|
||||
"nameSeparatorDescription": "Sunucu adı ile araç/istek adını ayırmak için kullanılan karakter (varsayılan: -)",
|
||||
"restartRequired": "Yapılandırma kaydedildi. Tüm hizmetlerin yeni ayarları doğru şekilde yüklemesini sağlamak için uygulamayı yeniden başlatmanız önerilir.",
|
||||
"exportMcpSettings": "Ayarları Dışa Aktar",
|
||||
"mcpSettingsJson": "MCP Ayarları JSON",
|
||||
"mcpSettingsJsonDescription": "Yedekleme veya diğer araçlara taşıma için mevcut mcp_settings.json yapılandırmanızı görüntüleyin, kopyalayın veya indirin",
|
||||
"copyToClipboard": "Panoya Kopyala",
|
||||
"downloadJson": "JSON Olarak İndir",
|
||||
"exportSuccess": "Ayarlar başarıyla dışa aktarıldı",
|
||||
"exportError": "Ayarlar getirilemedi"
|
||||
},
|
||||
"dxt": {
|
||||
"upload": "Yükle",
|
||||
"uploadTitle": "DXT Uzantısı Yükle",
|
||||
"dropFileHere": ".dxt dosyanızı buraya bırakın",
|
||||
"orClickToSelect": "veya bilgisayarınızdan seçmek için tıklayın",
|
||||
"invalidFileType": "Lütfen geçerli bir .dxt dosyası seçin",
|
||||
"noFileSelected": "Lütfen yüklemek için bir .dxt dosyası seçin",
|
||||
"uploading": "Yükleniyor...",
|
||||
"uploadFailed": "DXT dosyası yüklenemedi",
|
||||
"installServer": "DXT'den MCP Sunucusu Yükle",
|
||||
"extensionInfo": "Uzantı Bilgisi",
|
||||
"name": "Ad",
|
||||
"version": "Sürüm",
|
||||
"description": "Açıklama",
|
||||
"author": "Geliştirici",
|
||||
"tools": "Araçlar",
|
||||
"serverName": "Sunucu Adı",
|
||||
"serverNamePlaceholder": "Bu sunucu için bir ad girin",
|
||||
"install": "Yükle",
|
||||
"installing": "Yükleniyor...",
|
||||
"installFailed": "DXT'den sunucu yüklenemedi",
|
||||
"serverExistsTitle": "Sunucu Zaten Mevcut",
|
||||
"serverExistsConfirm": "'{{serverName}}' sunucusu zaten mevcut. Yeni sürümle geçersiz kılmak istiyor musunuz?",
|
||||
"override": "Geçersiz Kıl"
|
||||
},
|
||||
"jsonImport": {
|
||||
"button": "İçe Aktar",
|
||||
"title": "JSON'dan Sunucuları İçe Aktar",
|
||||
"inputLabel": "Sunucu Yapılandırma JSON",
|
||||
"inputHelp": "Sunucu yapılandırma JSON'unuzu yapıştırın. STDIO, SSE ve HTTP (streamable-http) sunucu türlerini destekler.",
|
||||
"preview": "Önizle",
|
||||
"previewTitle": "İçe Aktarılacak Sunucuları Önizle",
|
||||
"import": "İçe Aktar",
|
||||
"importing": "İçe aktarılıyor...",
|
||||
"invalidFormat": "Geçersiz JSON formatı. JSON bir 'mcpServers' nesnesi içermelidir.",
|
||||
"parseError": "JSON ayrıştırılamadı. Lütfen formatı kontrol edip tekrar deneyin.",
|
||||
"addFailed": "Sunucu eklenemedi",
|
||||
"importFailed": "Sunucular içe aktarılamadı",
|
||||
"partialSuccess": "{{total}} sunucudan {{count}} tanesi başarıyla içe aktarıldı. Bazı sunucular başarısız oldu:"
|
||||
},
|
||||
"users": {
|
||||
"add": "Kullanıcı Ekle",
|
||||
"addNew": "Yeni Kullanıcı Ekle",
|
||||
"edit": "Kullanıcıyı Düzenle",
|
||||
"delete": "Kullanıcıyı Sil",
|
||||
"create": "Kullanıcı Oluştur",
|
||||
"update": "Kullanıcıyı Güncelle",
|
||||
"username": "Kullanıcı Adı",
|
||||
"password": "Şifre",
|
||||
"newPassword": "Yeni Şifre",
|
||||
"confirmPassword": "Şifreyi Onayla",
|
||||
"adminRole": "Yönetici",
|
||||
"admin": "Yönetici",
|
||||
"user": "Kullanıcı",
|
||||
"permissions": "İzinler",
|
||||
"adminPermissions": "Tam sistem erişimi",
|
||||
"userPermissions": "Sınırlı erişim",
|
||||
"currentUser": "Siz",
|
||||
"noUsers": "Kullanıcı bulunamadı",
|
||||
"adminRequired": "Kullanıcıları yönetmek için yönetici erişimi gereklidir",
|
||||
"usernameRequired": "Kullanıcı adı gereklidir",
|
||||
"passwordRequired": "Şifre gereklidir",
|
||||
"passwordTooShort": "Şifre en az 6 karakter uzunluğunda olmalıdır",
|
||||
"passwordMismatch": "Şifreler eşleşmiyor",
|
||||
"usernamePlaceholder": "Kullanıcı adını girin",
|
||||
"passwordPlaceholder": "Şifreyi girin",
|
||||
"newPasswordPlaceholder": "Mevcut şifreyi korumak için boş bırakın",
|
||||
"confirmPasswordPlaceholder": "Yeni şifreyi onaylayın",
|
||||
"createError": "Kullanıcı oluşturulamadı",
|
||||
"updateError": "Kullanıcı güncellenemedi",
|
||||
"deleteError": "Kullanıcı silinemedi",
|
||||
"statsError": "Kullanıcı istatistikleri getirilemedi",
|
||||
"deleteConfirmation": "'{{username}}' kullanıcısını silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
|
||||
"confirmDelete": "Kullanıcıyı Sil",
|
||||
"deleteWarning": "'{{username}}' kullanıcısını silmek istediğinizden emin misiniz? Bu işlem geri alınamaz."
|
||||
},
|
||||
"api": {
|
||||
"errors": {
|
||||
"readonly": "Demo ortamı için salt okunur",
|
||||
"invalid_credentials": "Geçersiz kullanıcı adı veya şifre",
|
||||
"serverNameRequired": "Sunucu adı gereklidir",
|
||||
"serverConfigRequired": "Sunucu yapılandırması gereklidir",
|
||||
"serverConfigInvalid": "Sunucu yapılandırması bir URL, OpenAPI şartname URL'si veya şema, ya da argümanlı komut içermelidir",
|
||||
"serverTypeInvalid": "Sunucu türü şunlardan biri olmalıdır: stdio, sse, streamable-http, openapi",
|
||||
"urlRequiredForType": "{{type}} sunucu türü için URL gereklidir",
|
||||
"openapiSpecRequired": "OpenAPI sunucu türü için OpenAPI şartname URL'si veya şema gereklidir",
|
||||
"headersInvalidFormat": "Başlıklar bir nesne olmalıdır",
|
||||
"headersNotSupportedForStdio": "Başlıklar stdio sunucu türü için desteklenmez",
|
||||
"serverNotFound": "Sunucu bulunamadı",
|
||||
"failedToRemoveServer": "Sunucu bulunamadı veya kaldırılamadı",
|
||||
"internalServerError": "Dahili sunucu hatası",
|
||||
"failedToGetServers": "Sunucu bilgileri alınamadı",
|
||||
"failedToGetServerSettings": "Sunucu ayarları alınamadı",
|
||||
"failedToGetServerConfig": "Sunucu yapılandırması alınamadı",
|
||||
"failedToSaveSettings": "Ayarlar kaydedilemedi",
|
||||
"toolNameRequired": "Sunucu adı ve araç adı gereklidir",
|
||||
"descriptionMustBeString": "Açıklama bir string olmalıdır",
|
||||
"groupIdRequired": "Grup ID gereklidir",
|
||||
"groupNameRequired": "Grup adı gereklidir",
|
||||
"groupNotFound": "Grup bulunamadı",
|
||||
"groupIdAndServerNameRequired": "Grup ID ve sunucu adı gereklidir",
|
||||
"groupOrServerNotFound": "Grup veya sunucu bulunamadı",
|
||||
"toolsMustBeAllOrArray": "Araçlar \"all\" veya bir string dizisi olmalıdır",
|
||||
"serverNameAndToolNameRequired": "Sunucu adı ve araç adı gereklidir",
|
||||
"usernameRequired": "Kullanıcı adı gereklidir",
|
||||
"userNotFound": "Kullanıcı bulunamadı",
|
||||
"failedToGetUsers": "Kullanıcı bilgileri alınamadı",
|
||||
"failedToGetUserInfo": "Kullanıcı bilgisi alınamadı",
|
||||
"failedToGetUserStats": "Kullanıcı istatistikleri alınamadı",
|
||||
"marketServerNameRequired": "Sunucu adı gereklidir",
|
||||
"marketServerNotFound": "Market sunucusu bulunamadı",
|
||||
"failedToGetMarketServers": "Market sunucuları bilgisi alınamadı",
|
||||
"failedToGetMarketServer": "Market sunucusu bilgisi alınamadı",
|
||||
"failedToGetMarketCategories": "Market kategorileri alınamadı",
|
||||
"failedToGetMarketTags": "Market etiketleri alınamadı",
|
||||
"failedToSearchMarketServers": "Market sunucuları aranamadı",
|
||||
"failedToFilterMarketServers": "Market sunucuları filtrelenemedi",
|
||||
"failedToProcessDxtFile": "DXT dosyası işlenemedi"
|
||||
},
|
||||
"success": {
|
||||
"serverCreated": "Sunucu başarıyla oluşturuldu",
|
||||
"serverUpdated": "Sunucu başarıyla güncellendi",
|
||||
"serverRemoved": "Sunucu başarıyla kaldırıldı",
|
||||
"serverToggled": "Sunucu durumu başarıyla değiştirildi",
|
||||
"toolToggled": "{{name}} aracı başarıyla {{action}}",
|
||||
"toolDescriptionUpdated": "{{name}} aracının açıklaması başarıyla güncellendi",
|
||||
"systemConfigUpdated": "Sistem yapılandırması başarıyla güncellendi",
|
||||
"groupCreated": "Grup başarıyla oluşturuldu",
|
||||
"groupUpdated": "Grup başarıyla güncellendi",
|
||||
"groupDeleted": "Grup başarıyla silindi",
|
||||
"serverAddedToGroup": "Sunucu başarıyla gruba eklendi",
|
||||
"serverRemovedFromGroup": "Sunucu başarıyla gruptan kaldırıldı",
|
||||
"serverToolsUpdated": "Sunucu araçları başarıyla güncellendi"
|
||||
}
|
||||
},
|
||||
"oauthCallback": {
|
||||
"authorizationFailed": "Yetkilendirme Başarısız",
|
||||
"authorizationFailedError": "Hata",
|
||||
"authorizationFailedDetails": "Detaylar",
|
||||
"invalidRequest": "Geçersiz İstek",
|
||||
"missingStateParameter": "Gerekli OAuth durum parametresi eksik.",
|
||||
"missingCodeParameter": "Gerekli yetkilendirme kodu parametresi eksik.",
|
||||
"serverNotFound": "Sunucu Bulunamadı",
|
||||
"serverNotFoundMessage": "Bu yetkilendirme isteğiyle ilişkili sunucu bulunamadı.",
|
||||
"sessionExpiredMessage": "Yetkilendirme oturumunun süresi dolmuş olabilir. Lütfen tekrar yetkilendirmeyi deneyin.",
|
||||
"authorizationSuccessful": "Yetkilendirme Başarılı",
|
||||
"server": "Sunucu",
|
||||
"status": "Durum",
|
||||
"connected": "Bağlandı",
|
||||
"successMessage": "Sunucu başarıyla yetkilendirildi ve bağlandı.",
|
||||
"autoCloseMessage": "Bu pencere 3 saniye içinde otomatik olarak kapanacak...",
|
||||
"closeNow": "Şimdi Kapat",
|
||||
"connectionError": "Bağlantı Hatası",
|
||||
"connectionErrorMessage": "Yetkilendirme başarılı oldu, ancak sunucuya bağlanılamadı.",
|
||||
"reconnectMessage": "Lütfen kontrol panelinden yeniden bağlanmayı deneyin.",
|
||||
"configurationError": "Yapılandırma Hatası",
|
||||
"configurationErrorMessage": "Sunucu aktarımı OAuth finishAuth() desteklemiyor. Lütfen sunucunun streamable-http aktarımıyla yapılandırıldığından emin olun.",
|
||||
"internalError": "İçsel Hata",
|
||||
"internalErrorMessage": "OAuth geri araması işlenirken beklenmeyen bir hata oluştu.",
|
||||
"closeWindow": "Pencereyi Kapat"
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@
|
||||
"i18next-fs-backend": "^2.6.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^2.0.2",
|
||||
"openai": "^6.7.0",
|
||||
"openai": "^4.104.0",
|
||||
"openapi-types": "^12.1.3",
|
||||
"openid-client": "^6.8.1",
|
||||
"pg": "^8.16.3",
|
||||
@@ -105,12 +105,12 @@
|
||||
"jest": "^30.2.0",
|
||||
"jest-environment-node": "^30.0.5",
|
||||
"jest-mock-extended": "4.0.0",
|
||||
"lucide-react": "^0.552.0",
|
||||
"lucide-react": "^0.486.0",
|
||||
"next": "^15.5.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-i18next": "^15.7.2",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"supertest": "^7.1.4",
|
||||
|
||||
353
pnpm-lock.yaml
generated
353
pnpm-lock.yaml
generated
@@ -35,7 +35,7 @@ importers:
|
||||
version: 0.5.16
|
||||
axios:
|
||||
specifier: ^1.12.2
|
||||
version: 1.13.1
|
||||
version: 1.12.2
|
||||
bcrypt:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
@@ -59,7 +59,7 @@ importers:
|
||||
version: 7.2.1
|
||||
i18next:
|
||||
specifier: ^25.5.0
|
||||
version: 25.6.0(typescript@5.9.2)
|
||||
version: 25.5.0(typescript@5.9.2)
|
||||
i18next-fs-backend:
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0
|
||||
@@ -70,8 +70,8 @@ importers:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2
|
||||
openai:
|
||||
specifier: ^6.7.0
|
||||
version: 6.7.0(zod@3.25.76)
|
||||
specifier: ^4.104.0
|
||||
version: 4.104.0(zod@3.25.76)
|
||||
openapi-types:
|
||||
specifier: ^12.1.3
|
||||
version: 12.1.3
|
||||
@@ -99,10 +99,10 @@ importers:
|
||||
devDependencies:
|
||||
'@radix-ui/react-accordion':
|
||||
specifier: ^1.2.12
|
||||
version: 1.2.12(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
version: 1.2.12(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-slot':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3(@types/react@19.2.2)(react@19.1.1)
|
||||
version: 1.2.3(@types/react@19.1.11)(react@19.1.1)
|
||||
'@shadcn/ui':
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4
|
||||
@@ -141,10 +141,10 @@ importers:
|
||||
version: 24.6.2
|
||||
'@types/react':
|
||||
specifier: ^19.1.11
|
||||
version: 19.2.2
|
||||
version: 19.1.11
|
||||
'@types/react-dom':
|
||||
specifier: ^19.1.7
|
||||
version: 19.1.7(@types/react@19.2.2)
|
||||
version: 19.1.7(@types/react@19.1.11)
|
||||
'@types/supertest':
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3
|
||||
@@ -188,8 +188,8 @@ importers:
|
||||
specifier: 4.0.0
|
||||
version: 4.0.0(@jest/globals@30.2.0)(jest@30.2.0(@types/node@24.6.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@24.6.2)(typescript@5.9.2)))(typescript@5.9.2)
|
||||
lucide-react:
|
||||
specifier: ^0.552.0
|
||||
version: 0.552.0(react@19.1.1)
|
||||
specifier: ^0.486.0
|
||||
version: 0.486.0(react@19.1.1)
|
||||
next:
|
||||
specifier: ^15.5.0
|
||||
version: 15.5.2(@babel/core@7.28.4)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -200,14 +200,14 @@ importers:
|
||||
specifier: ^3.6.2
|
||||
version: 3.6.2
|
||||
react:
|
||||
specifier: 19.1.1
|
||||
specifier: ^19.1.1
|
||||
version: 19.1.1
|
||||
react-dom:
|
||||
specifier: 19.1.1
|
||||
specifier: ^19.1.1
|
||||
version: 19.1.1(react@19.1.1)
|
||||
react-i18next:
|
||||
specifier: ^15.7.2
|
||||
version: 15.7.2(i18next@25.6.0(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
|
||||
version: 15.7.2(i18next@25.5.0(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
|
||||
react-router-dom:
|
||||
specifier: ^7.8.2
|
||||
version: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -447,10 +447,6 @@ packages:
|
||||
resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/runtime@7.28.4':
|
||||
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -856,92 +852,78 @@ packages:
|
||||
resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.2.0':
|
||||
resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.2.0':
|
||||
resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.0':
|
||||
resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.2.0':
|
||||
resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.2.0':
|
||||
resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.2.0':
|
||||
resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.34.3':
|
||||
resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.34.3':
|
||||
resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.34.3':
|
||||
resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.3':
|
||||
resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.34.3':
|
||||
resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.34.3':
|
||||
resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.34.3':
|
||||
resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.34.3':
|
||||
resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
|
||||
@@ -1133,28 +1115,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-arm64-musl@15.5.2':
|
||||
resolution: {integrity: sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-linux-x64-gnu@15.5.2':
|
||||
resolution: {integrity: sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-x64-musl@15.5.2':
|
||||
resolution: {integrity: sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@15.5.2':
|
||||
resolution: {integrity: sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==}
|
||||
@@ -1372,67 +1350,56 @@ packages:
|
||||
resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.52.5':
|
||||
resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.52.5':
|
||||
resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.52.5':
|
||||
resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.52.5':
|
||||
resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.52.5':
|
||||
resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.52.5':
|
||||
resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
|
||||
@@ -1498,28 +1465,24 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.13.5':
|
||||
resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.13.5':
|
||||
resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.13.5':
|
||||
resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.13.5':
|
||||
resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==}
|
||||
@@ -1639,56 +1602,48 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.14':
|
||||
resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.12':
|
||||
resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.14':
|
||||
resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.12':
|
||||
resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.14':
|
||||
resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.12':
|
||||
resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.14':
|
||||
resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.12':
|
||||
resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==}
|
||||
@@ -1845,6 +1800,12 @@ packages:
|
||||
'@types/multer@1.4.13':
|
||||
resolution: {integrity: sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==}
|
||||
|
||||
'@types/node-fetch@2.6.13':
|
||||
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
||||
|
||||
'@types/node@18.19.129':
|
||||
resolution: {integrity: sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A==}
|
||||
|
||||
'@types/node@24.6.2':
|
||||
resolution: {integrity: sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==}
|
||||
|
||||
@@ -1862,8 +1823,8 @@ packages:
|
||||
peerDependencies:
|
||||
'@types/react': ^19.0.0
|
||||
|
||||
'@types/react@19.2.2':
|
||||
resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==}
|
||||
'@types/react@19.1.11':
|
||||
resolution: {integrity: sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==}
|
||||
|
||||
'@types/semver@7.7.0':
|
||||
resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==}
|
||||
@@ -2019,49 +1980,41 @@ packages:
|
||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||
@@ -2089,6 +2042,10 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
||||
accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -2115,6 +2072,10 @@ packages:
|
||||
resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==}
|
||||
engines: {node: '>=12.0'}
|
||||
|
||||
agentkeepalive@4.6.0:
|
||||
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
|
||||
ajv-draft-04@1.0.0:
|
||||
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
|
||||
peerDependencies:
|
||||
@@ -2205,8 +2166,8 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.13.1:
|
||||
resolution: {integrity: sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==}
|
||||
axios@1.12.2:
|
||||
resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==}
|
||||
|
||||
babel-jest@30.2.0:
|
||||
resolution: {integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==}
|
||||
@@ -2712,6 +2673,10 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
eventsource-parser@3.0.5:
|
||||
resolution: {integrity: sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
@@ -2840,10 +2805,17 @@ packages:
|
||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
form-data-encoder@1.7.2:
|
||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||
|
||||
form-data@4.0.4:
|
||||
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
formdata-node@4.4.1:
|
||||
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
||||
engines: {node: '>= 12.20'}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
@@ -2985,14 +2957,17 @@ packages:
|
||||
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
|
||||
engines: {node: '>=14.18.0'}
|
||||
|
||||
humanize-ms@1.2.1:
|
||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||
|
||||
i18next-browser-languagedetector@8.2.0:
|
||||
resolution: {integrity: sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==}
|
||||
|
||||
i18next-fs-backend@2.6.0:
|
||||
resolution: {integrity: sha512-3ZlhNoF9yxnM8pa8bWp5120/Ob6t4lVl1l/tbLmkml/ei3ud8IWySCHt2lrY5xWRlSU5D9IV2sm5bEbGuTqwTw==}
|
||||
|
||||
i18next@25.6.0:
|
||||
resolution: {integrity: sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==}
|
||||
i18next@25.5.0:
|
||||
resolution: {integrity: sha512-Mm2CgIq0revRFbBvfzqW9kDw1r44M4VDWC+YNRx9vTo5bU/iogSdEAC2HEonDA4czEce/iSbAkK90Tw7UrRZKA==}
|
||||
peerDependencies:
|
||||
typescript: ^5
|
||||
peerDependenciesMeta:
|
||||
@@ -3394,28 +3369,24 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.1:
|
||||
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.1:
|
||||
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||
@@ -3484,8 +3455,8 @@ packages:
|
||||
lru-cache@5.1.1:
|
||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
|
||||
lucide-react@0.552.0:
|
||||
resolution: {integrity: sha512-g9WCjmfwqbexSnZE+2cl21PCfXOcqnGeWeMTNAOGEfpPbm/ZF4YIq77Z8qWrxbu660EKuLB4nSLggoKnCb+isw==}
|
||||
lucide-react@0.486.0:
|
||||
resolution: {integrity: sha512-xWop/wMsC1ikiEVLZrxXjPKw4vU/eAip33G2mZHgbWnr4Nr5Rt4Vx4s/q1D3B/rQVbxjOuqASkEZcUxDEKzecw==}
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
@@ -3677,6 +3648,15 @@ packages:
|
||||
engines: {node: '>=10.5.0'}
|
||||
deprecated: Use your platform's native DOMException instead
|
||||
|
||||
node-fetch@2.7.0:
|
||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
node-fetch@3.3.2:
|
||||
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -3733,12 +3713,12 @@ packages:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
openai@6.7.0:
|
||||
resolution: {integrity: sha512-mgSQXa3O/UXTbA8qFzoa7aydbXBJR5dbLQXCRapAOtoNT+v69sLdKMZzgiakpqhclRnhPggPAXoniVGn2kMY2A==}
|
||||
openai@4.104.0:
|
||||
resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
ws: ^8.18.0
|
||||
zod: ^3.25 || ^4.0
|
||||
zod: ^3.23.8
|
||||
peerDependenciesMeta:
|
||||
ws:
|
||||
optional: true
|
||||
@@ -4386,6 +4366,9 @@ packages:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
tree-kill@1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
@@ -4568,6 +4551,9 @@ packages:
|
||||
engines: {node: '>=0.8.0'}
|
||||
hasBin: true
|
||||
|
||||
undici-types@5.26.5:
|
||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||
|
||||
undici-types@7.13.0:
|
||||
resolution: {integrity: sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==}
|
||||
|
||||
@@ -4671,6 +4657,16 @@ packages:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3:
|
||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
|
||||
which-typed-array@1.1.19:
|
||||
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -4983,8 +4979,6 @@ snapshots:
|
||||
|
||||
'@babel/runtime@7.28.3': {}
|
||||
|
||||
'@babel/runtime@7.28.4': {}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
@@ -5662,122 +5656,122 @@ snapshots:
|
||||
|
||||
'@radix-ui/primitive@1.1.3': {}
|
||||
|
||||
'@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.1.7(@types/react@19.2.2)
|
||||
'@types/react': 19.1.11
|
||||
'@types/react-dom': 19.1.7(@types/react@19.1.11)
|
||||
|
||||
'@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.1.7(@types/react@19.2.2)
|
||||
'@types/react': 19.1.11
|
||||
'@types/react-dom': 19.1.7(@types/react@19.1.11)
|
||||
|
||||
'@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.1.7(@types/react@19.2.2)
|
||||
'@types/react': 19.1.11
|
||||
'@types/react-dom': 19.1.7(@types/react@19.1.11)
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-context@1.1.2(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-direction@1.1.1(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-id@1.1.1(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.1.7(@types/react@19.2.2)
|
||||
'@types/react': 19.1.11
|
||||
'@types/react-dom': 19.1.7(@types/react@19.1.11)
|
||||
|
||||
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.1.7(@types/react@19.2.2)
|
||||
'@types/react': 19.1.11
|
||||
'@types/react-dom': 19.1.7(@types/react@19.1.11)
|
||||
|
||||
'@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-slot@1.2.3(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.11)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.1.1)':
|
||||
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.11)(react@19.1.1)':
|
||||
dependencies:
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.27': {}
|
||||
|
||||
@@ -6191,6 +6185,15 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/express': 4.17.23
|
||||
|
||||
'@types/node-fetch@2.6.13':
|
||||
dependencies:
|
||||
'@types/node': 24.6.2
|
||||
form-data: 4.0.4
|
||||
|
||||
'@types/node@18.19.129':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@24.6.2':
|
||||
dependencies:
|
||||
undici-types: 7.13.0
|
||||
@@ -6205,11 +6208,11 @@ snapshots:
|
||||
|
||||
'@types/range-parser@1.2.7': {}
|
||||
|
||||
'@types/react-dom@19.1.7(@types/react@19.2.2)':
|
||||
'@types/react-dom@19.1.7(@types/react@19.1.11)':
|
||||
dependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react': 19.1.11
|
||||
|
||||
'@types/react@19.2.2':
|
||||
'@types/react@19.1.11':
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
@@ -6438,6 +6441,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
accepts@1.3.8:
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
@@ -6460,6 +6467,10 @@ snapshots:
|
||||
|
||||
adm-zip@0.5.16: {}
|
||||
|
||||
agentkeepalive@4.6.0:
|
||||
dependencies:
|
||||
humanize-ms: 1.2.1
|
||||
|
||||
ajv-draft-04@1.0.0(ajv@8.17.1):
|
||||
optionalDependencies:
|
||||
ajv: 8.17.1
|
||||
@@ -6537,7 +6548,7 @@ snapshots:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.1.0
|
||||
|
||||
axios@1.13.1:
|
||||
axios@1.12.2:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.11
|
||||
form-data: 4.0.4
|
||||
@@ -7113,6 +7124,8 @@ snapshots:
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
eventsource-parser@3.0.5: {}
|
||||
|
||||
eventsource@3.0.7:
|
||||
@@ -7326,6 +7339,8 @@ snapshots:
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
form-data-encoder@1.7.2: {}
|
||||
|
||||
form-data@4.0.4:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
@@ -7334,6 +7349,11 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
mime-types: 2.1.35
|
||||
|
||||
formdata-node@4.4.1:
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 4.0.0-beta.3
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
@@ -7483,15 +7503,19 @@ snapshots:
|
||||
|
||||
human-signals@4.3.1: {}
|
||||
|
||||
humanize-ms@1.2.1:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
i18next-browser-languagedetector@8.2.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.3
|
||||
|
||||
i18next-fs-backend@2.6.0: {}
|
||||
|
||||
i18next@25.6.0(typescript@5.9.2):
|
||||
i18next@25.5.0(typescript@5.9.2):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@babel/runtime': 7.28.3
|
||||
optionalDependencies:
|
||||
typescript: 5.9.2
|
||||
|
||||
@@ -8139,7 +8163,7 @@ snapshots:
|
||||
dependencies:
|
||||
yallist: 3.1.1
|
||||
|
||||
lucide-react@0.552.0(react@19.1.1):
|
||||
lucide-react@0.486.0(react@19.1.1):
|
||||
dependencies:
|
||||
react: 19.1.1
|
||||
|
||||
@@ -8287,6 +8311,10 @@ snapshots:
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-fetch@3.3.2:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.1
|
||||
@@ -8333,9 +8361,19 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
|
||||
openai@6.7.0(zod@3.25.76):
|
||||
openai@4.104.0(zod@3.25.76):
|
||||
dependencies:
|
||||
'@types/node': 18.19.129
|
||||
'@types/node-fetch': 2.6.13
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.6.0
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0
|
||||
optionalDependencies:
|
||||
zod: 3.25.76
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
openapi-types@12.1.3: {}
|
||||
|
||||
@@ -8561,11 +8599,11 @@ snapshots:
|
||||
react: 19.1.1
|
||||
scheduler: 0.26.0
|
||||
|
||||
react-i18next@15.7.2(i18next@25.6.0(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2):
|
||||
react-i18next@15.7.2(i18next@25.5.0(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.3
|
||||
html-parse-stringify: 3.0.1
|
||||
i18next: 25.6.0(typescript@5.9.2)
|
||||
i18next: 25.5.0(typescript@5.9.2)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
@@ -9021,6 +9059,8 @@ snapshots:
|
||||
|
||||
toidentifier@1.0.1: {}
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
ts-api-utils@1.4.3(typescript@5.9.2):
|
||||
@@ -9165,6 +9205,8 @@ snapshots:
|
||||
uglify-js@3.19.3:
|
||||
optional: true
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
|
||||
undici-types@7.13.0: {}
|
||||
|
||||
universalify@2.0.1: {}
|
||||
@@ -9250,6 +9292,15 @@ snapshots:
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3: {}
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
|
||||
which-typed-array@1.1.19:
|
||||
dependencies:
|
||||
available-typed-arrays: 1.0.7
|
||||
|
||||
@@ -369,6 +369,118 @@ export const createTransportFromConfig = async (name: string, conf: ServerConfig
|
||||
return transport;
|
||||
};
|
||||
|
||||
// Helper function to connect an on-demand server temporarily
|
||||
const connectOnDemandServer = async (serverInfo: ServerInfo): Promise<void> => {
|
||||
if (!serverInfo.config) {
|
||||
throw new Error(`Server configuration not found for on-demand server: ${serverInfo.name}`);
|
||||
}
|
||||
|
||||
console.log(`Connecting on-demand server: ${serverInfo.name}`);
|
||||
|
||||
// Create transport
|
||||
const transport = await createTransportFromConfig(serverInfo.name, serverInfo.config);
|
||||
|
||||
// Create client
|
||||
const client = new Client(
|
||||
{
|
||||
name: `mcp-client-${serverInfo.name}`,
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
prompts: {},
|
||||
resources: {},
|
||||
tools: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Get request options from server configuration
|
||||
const serverRequestOptions = serverInfo.config.options || {};
|
||||
const requestOptions = {
|
||||
timeout: serverRequestOptions.timeout || 60000,
|
||||
resetTimeoutOnProgress: serverRequestOptions.resetTimeoutOnProgress || false,
|
||||
maxTotalTimeout: serverRequestOptions.maxTotalTimeout,
|
||||
};
|
||||
|
||||
// Connect the client
|
||||
await client.connect(transport, requestOptions);
|
||||
|
||||
// Update server info with client and transport
|
||||
serverInfo.client = client;
|
||||
serverInfo.transport = transport;
|
||||
serverInfo.options = requestOptions;
|
||||
serverInfo.status = 'connected';
|
||||
|
||||
console.log(`Successfully connected on-demand server: ${serverInfo.name}`);
|
||||
|
||||
// List tools if not already loaded
|
||||
if (serverInfo.tools.length === 0) {
|
||||
const capabilities = client.getServerCapabilities();
|
||||
if (capabilities?.tools) {
|
||||
try {
|
||||
const tools = await client.listTools({}, requestOptions);
|
||||
serverInfo.tools = tools.tools.map((tool) => ({
|
||||
name: `${serverInfo.name}${getNameSeparator()}${tool.name}`,
|
||||
description: tool.description || '',
|
||||
inputSchema: cleanInputSchema(tool.inputSchema || {}),
|
||||
}));
|
||||
// Save tools as vector embeddings for search
|
||||
saveToolsAsVectorEmbeddings(serverInfo.name, serverInfo.tools);
|
||||
console.log(`Loaded ${serverInfo.tools.length} tools for on-demand server: ${serverInfo.name}`);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to list tools for on-demand server ${serverInfo.name}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// List prompts if available
|
||||
if (capabilities?.prompts) {
|
||||
try {
|
||||
const prompts = await client.listPrompts({}, requestOptions);
|
||||
serverInfo.prompts = prompts.prompts.map((prompt) => ({
|
||||
name: `${serverInfo.name}${getNameSeparator()}${prompt.name}`,
|
||||
title: prompt.title,
|
||||
description: prompt.description,
|
||||
arguments: prompt.arguments,
|
||||
}));
|
||||
console.log(`Loaded ${serverInfo.prompts.length} prompts for on-demand server: ${serverInfo.name}`);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to list prompts for on-demand server ${serverInfo.name}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to disconnect an on-demand server
|
||||
const disconnectOnDemandServer = (serverInfo: ServerInfo): void => {
|
||||
if (serverInfo.connectionMode !== 'on-demand') {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Disconnecting on-demand server: ${serverInfo.name}`);
|
||||
|
||||
try {
|
||||
if (serverInfo.client) {
|
||||
serverInfo.client.close();
|
||||
serverInfo.client = undefined;
|
||||
}
|
||||
if (serverInfo.transport) {
|
||||
serverInfo.transport.close();
|
||||
serverInfo.transport = undefined;
|
||||
}
|
||||
serverInfo.status = 'disconnected';
|
||||
console.log(`Successfully disconnected on-demand server: ${serverInfo.name}`);
|
||||
} catch (error) {
|
||||
// Log disconnect errors but don't throw - this is cleanup code that shouldn't fail the request
|
||||
// The connection is likely already closed if we get an error here
|
||||
console.warn(`Error disconnecting on-demand server ${serverInfo.name}:`, error);
|
||||
// Force status to disconnected even if cleanup had errors
|
||||
serverInfo.status = 'disconnected';
|
||||
serverInfo.client = undefined;
|
||||
serverInfo.transport = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to handle client.callTool with reconnection logic
|
||||
const callToolWithReconnect = async (
|
||||
serverInfo: ServerInfo,
|
||||
@@ -529,7 +641,6 @@ export const initializeClientsFromSettings = async (
|
||||
continue;
|
||||
}
|
||||
|
||||
let transport;
|
||||
let openApiClient;
|
||||
if (expandedConf.type === 'openapi') {
|
||||
// Handle OpenAPI type servers
|
||||
@@ -600,10 +711,43 @@ export const initializeClientsFromSettings = async (
|
||||
serverInfo.error = `Failed to initialize OpenAPI server: ${error}`;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
transport = await createTransportFromConfig(name, expandedConf);
|
||||
}
|
||||
|
||||
// Handle on-demand connection mode servers
|
||||
// These servers connect briefly to get tools list, then disconnect
|
||||
const connectionMode = expandedConf.connectionMode || 'persistent';
|
||||
if (connectionMode === 'on-demand') {
|
||||
console.log(`Initializing on-demand server: ${name}`);
|
||||
const serverInfo: ServerInfo = {
|
||||
name,
|
||||
owner: expandedConf.owner,
|
||||
status: 'disconnected',
|
||||
error: null,
|
||||
tools: [],
|
||||
prompts: [],
|
||||
createTime: Date.now(),
|
||||
enabled: expandedConf.enabled === undefined ? true : expandedConf.enabled,
|
||||
connectionMode: 'on-demand',
|
||||
config: expandedConf,
|
||||
};
|
||||
nextServerInfos.push(serverInfo);
|
||||
|
||||
// Connect briefly to get tools list, then disconnect
|
||||
try {
|
||||
await connectOnDemandServer(serverInfo);
|
||||
console.log(`Successfully initialized on-demand server: ${name} with ${serverInfo.tools.length} tools`);
|
||||
// Disconnect immediately after getting tools
|
||||
disconnectOnDemandServer(serverInfo);
|
||||
} catch (error) {
|
||||
console.error(`Failed to initialize on-demand server ${name}:`, error);
|
||||
serverInfo.error = `Failed to initialize: ${error}`;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create transport for persistent connection mode servers (not OpenAPI, already handled above)
|
||||
const transport = await createTransportFromConfig(name, expandedConf);
|
||||
|
||||
const client = new Client(
|
||||
{
|
||||
name: `mcp-client-${name}`,
|
||||
@@ -644,6 +788,7 @@ export const initializeClientsFromSettings = async (
|
||||
transport,
|
||||
options: requestOptions,
|
||||
createTime: Date.now(),
|
||||
connectionMode: connectionMode,
|
||||
config: expandedConf, // Store reference to expanded config
|
||||
};
|
||||
|
||||
@@ -1011,8 +1156,11 @@ export const handleListToolsRequest = async (_: any, extra: any) => {
|
||||
const targetGroup = group?.startsWith('$smart/') ? group.substring(7) : undefined;
|
||||
|
||||
// Get info about available servers, filtered by target group if specified
|
||||
// Include both connected persistent servers and on-demand servers (even if disconnected)
|
||||
let availableServers = serverInfos.filter(
|
||||
(server) => server.status === 'connected' && server.enabled !== false,
|
||||
(server) =>
|
||||
server.enabled !== false &&
|
||||
(server.status === 'connected' || server.connectionMode === 'on-demand'),
|
||||
);
|
||||
|
||||
// If a target group is specified, filter servers to only those in the group
|
||||
@@ -1139,6 +1287,10 @@ Available servers: ${serversList}`,
|
||||
export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
console.log(`Handling CallToolRequest for tool: ${JSON.stringify(request.params)}`);
|
||||
try {
|
||||
// Note: On-demand server connection and disconnection are handled in the specific
|
||||
// code paths below (call_tool and regular tool handling) with try-finally blocks.
|
||||
// This outer try-catch only handles errors from operations that don't connect servers.
|
||||
|
||||
// Special handling for agent group tools
|
||||
if (request.params.name === 'search_tools') {
|
||||
const { query, limit = 10 } = request.params.arguments || {};
|
||||
@@ -1284,10 +1436,11 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
targetServerInfo = getServerByName(extra.server);
|
||||
} else {
|
||||
// Find the first server that has this tool
|
||||
// Include both connected servers and on-demand servers (even if disconnected)
|
||||
targetServerInfo = serverInfos.find(
|
||||
(serverInfo) =>
|
||||
serverInfo.status === 'connected' &&
|
||||
serverInfo.enabled !== false &&
|
||||
(serverInfo.status === 'connected' || serverInfo.connectionMode === 'on-demand') &&
|
||||
serverInfo.tools.some((tool) => tool.name === toolName),
|
||||
);
|
||||
}
|
||||
@@ -1363,6 +1516,11 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
}
|
||||
|
||||
// Call the tool on the target server (MCP servers)
|
||||
// Connect on-demand server if needed
|
||||
if (targetServerInfo.connectionMode === 'on-demand' && !targetServerInfo.client) {
|
||||
await connectOnDemandServer(targetServerInfo);
|
||||
}
|
||||
|
||||
const client = targetServerInfo.client;
|
||||
if (!client) {
|
||||
throw new Error(`Client not found for server: ${targetServerInfo.name}`);
|
||||
@@ -1379,17 +1537,23 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
const separator = getNameSeparator();
|
||||
const prefix = `${targetServerInfo.name}${separator}`;
|
||||
toolName = toolName.startsWith(prefix) ? toolName.substring(prefix.length) : toolName;
|
||||
const result = await callToolWithReconnect(
|
||||
targetServerInfo,
|
||||
{
|
||||
name: toolName,
|
||||
arguments: finalArgs,
|
||||
},
|
||||
targetServerInfo.options || {},
|
||||
);
|
||||
|
||||
try {
|
||||
const result = await callToolWithReconnect(
|
||||
targetServerInfo,
|
||||
{
|
||||
name: toolName,
|
||||
arguments: finalArgs,
|
||||
},
|
||||
targetServerInfo.options || {},
|
||||
);
|
||||
|
||||
console.log(`Tool invocation result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
console.log(`Tool invocation result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
} finally {
|
||||
// Disconnect on-demand server after tool call
|
||||
disconnectOnDemandServer(targetServerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Regular tool handling
|
||||
@@ -1459,6 +1623,11 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
}
|
||||
|
||||
// Handle MCP servers
|
||||
// Connect on-demand server if needed
|
||||
if (serverInfo.connectionMode === 'on-demand' && !serverInfo.client) {
|
||||
await connectOnDemandServer(serverInfo);
|
||||
}
|
||||
|
||||
const client = serverInfo.client;
|
||||
if (!client) {
|
||||
throw new Error(`Client not found for server: ${serverInfo.name}`);
|
||||
@@ -1469,13 +1638,19 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
|
||||
request.params.name = request.params.name.startsWith(prefix)
|
||||
? request.params.name.substring(prefix.length)
|
||||
: request.params.name;
|
||||
const result = await callToolWithReconnect(
|
||||
serverInfo,
|
||||
request.params,
|
||||
serverInfo.options || {},
|
||||
);
|
||||
console.log(`Tool call result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
|
||||
try {
|
||||
const result = await callToolWithReconnect(
|
||||
serverInfo,
|
||||
request.params,
|
||||
serverInfo.options || {},
|
||||
);
|
||||
console.log(`Tool call result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
} finally {
|
||||
// Disconnect on-demand server after tool call
|
||||
disconnectOnDemandServer(serverInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error handling CallToolRequest: ${error}`);
|
||||
return {
|
||||
|
||||
@@ -204,6 +204,7 @@ export interface ServerConfig {
|
||||
enabled?: boolean; // Flag to enable/disable the server
|
||||
owner?: string; // Owner of the server, defaults to 'admin' user
|
||||
keepAliveInterval?: number; // Keep-alive ping interval in milliseconds (default: 60000ms for SSE servers)
|
||||
connectionMode?: 'persistent' | 'on-demand'; // Connection strategy: 'persistent' maintains long-running connections (default), 'on-demand' connects only when tools are called
|
||||
tools?: Record<string, { enabled: boolean; description?: string }>; // Tool-specific configurations with enable/disable state and custom descriptions
|
||||
prompts?: Record<string, { enabled: boolean; description?: string }>; // Prompt-specific configurations with enable/disable state and custom descriptions
|
||||
options?: Partial<Pick<RequestOptions, 'timeout' | 'resetTimeoutOnProgress' | 'maxTotalTimeout'>>; // MCP request options configuration
|
||||
@@ -312,6 +313,7 @@ export interface ServerInfo {
|
||||
options?: RequestOptions; // Options for requests
|
||||
createTime: number; // Timestamp of when the server was created
|
||||
enabled?: boolean; // Flag to indicate if the server is enabled
|
||||
connectionMode?: 'persistent' | 'on-demand'; // Connection strategy for this server
|
||||
keepAliveIntervalId?: NodeJS.Timeout; // Timer ID for keep-alive ping interval
|
||||
config?: ServerConfig; // Reference to the original server configuration for OpenAPI passthrough headers
|
||||
oauth?: {
|
||||
|
||||
340
tests/services/mcpService-on-demand.test.ts
Normal file
340
tests/services/mcpService-on-demand.test.ts
Normal file
@@ -0,0 +1,340 @@
|
||||
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
|
||||
|
||||
// Mock dependencies before importing mcpService
|
||||
jest.mock('../../src/services/oauthService.js', () => ({
|
||||
initializeAllOAuthClients: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/oauthClientRegistration.js', () => ({
|
||||
registerOAuthClient: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/mcpOAuthProvider.js', () => ({
|
||||
createOAuthProvider: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/groupService.js', () => ({
|
||||
getServersInGroup: jest.fn(),
|
||||
getServerConfigInGroup: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/sseService.js', () => ({
|
||||
getGroup: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/vectorSearchService.js', () => ({
|
||||
saveToolsAsVectorEmbeddings: jest.fn(),
|
||||
searchToolsByVector: jest.fn(() => Promise.resolve([])),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/services/services.js', () => ({
|
||||
getDataService: jest.fn(() => ({
|
||||
filterData: (data: any) => data,
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/config/index.js', () => ({
|
||||
default: {
|
||||
mcpHubName: 'test-hub',
|
||||
mcpHubVersion: '1.0.0',
|
||||
initTimeout: 60000,
|
||||
},
|
||||
loadSettings: jest.fn(() => ({})),
|
||||
expandEnvVars: jest.fn((val: string) => val),
|
||||
replaceEnvVars: jest.fn((obj: any) => obj),
|
||||
getNameSeparator: jest.fn(() => '-'),
|
||||
}));
|
||||
|
||||
// Mock Client
|
||||
const mockClient = {
|
||||
connect: jest.fn(),
|
||||
close: jest.fn(),
|
||||
listTools: jest.fn(),
|
||||
listPrompts: jest.fn(),
|
||||
getServerCapabilities: jest.fn(() => ({
|
||||
tools: {},
|
||||
prompts: {},
|
||||
})),
|
||||
callTool: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('@modelcontextprotocol/sdk/client/index.js', () => ({
|
||||
Client: jest.fn(() => mockClient),
|
||||
}));
|
||||
|
||||
// Mock StdioClientTransport
|
||||
const mockTransport = {
|
||||
close: jest.fn(),
|
||||
stderr: null,
|
||||
};
|
||||
|
||||
jest.mock('@modelcontextprotocol/sdk/client/stdio.js', () => ({
|
||||
StdioClientTransport: jest.fn(() => mockTransport),
|
||||
}));
|
||||
|
||||
// Mock DAO
|
||||
const mockServerDao = {
|
||||
findAll: jest.fn(),
|
||||
findById: jest.fn(),
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
exists: jest.fn(),
|
||||
setEnabled: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('../../src/dao/index.js', () => ({
|
||||
getServerDao: jest.fn(() => mockServerDao),
|
||||
}));
|
||||
|
||||
import { initializeClientsFromSettings, handleCallToolRequest } from '../../src/services/mcpService.js';
|
||||
|
||||
describe('On-Demand MCP Server Connection Mode', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockClient.connect.mockResolvedValue(undefined);
|
||||
mockClient.close.mockReturnValue(undefined);
|
||||
mockClient.listTools.mockResolvedValue({
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'Test tool',
|
||||
inputSchema: { type: 'object' },
|
||||
},
|
||||
],
|
||||
});
|
||||
mockClient.listPrompts.mockResolvedValue({
|
||||
prompts: [],
|
||||
});
|
||||
mockClient.callTool.mockResolvedValue({
|
||||
content: [{ type: 'text', text: 'Success' }],
|
||||
});
|
||||
mockTransport.close.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('Server Initialization', () => {
|
||||
it('should not maintain persistent connection for on-demand servers', async () => {
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'on-demand-server',
|
||||
command: 'node',
|
||||
args: ['test.js'],
|
||||
connectionMode: 'on-demand',
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const serverInfos = await initializeClientsFromSettings(true);
|
||||
|
||||
expect(serverInfos).toHaveLength(1);
|
||||
expect(serverInfos[0].name).toBe('on-demand-server');
|
||||
expect(serverInfos[0].connectionMode).toBe('on-demand');
|
||||
expect(serverInfos[0].status).toBe('disconnected');
|
||||
// Should connect once to get tools, then disconnect
|
||||
expect(mockClient.connect).toHaveBeenCalledTimes(1);
|
||||
expect(mockTransport.close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should load tools during initialization for on-demand servers', async () => {
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'on-demand-server',
|
||||
command: 'node',
|
||||
args: ['test.js'],
|
||||
connectionMode: 'on-demand',
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const serverInfos = await initializeClientsFromSettings(true);
|
||||
|
||||
expect(serverInfos[0].tools).toHaveLength(1);
|
||||
expect(serverInfos[0].tools[0].name).toBe('on-demand-server-test-tool');
|
||||
expect(mockClient.listTools).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should maintain persistent connection for default connection mode', async () => {
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'persistent-server',
|
||||
command: 'node',
|
||||
args: ['test.js'],
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const serverInfos = await initializeClientsFromSettings(true);
|
||||
|
||||
expect(serverInfos).toHaveLength(1);
|
||||
expect(serverInfos[0].connectionMode).toBe('persistent');
|
||||
expect(mockClient.connect).toHaveBeenCalledTimes(1);
|
||||
// Should not disconnect immediately
|
||||
expect(mockTransport.close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle initialization errors for on-demand servers gracefully', async () => {
|
||||
mockClient.connect.mockRejectedValueOnce(new Error('Connection failed'));
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'failing-server',
|
||||
command: 'node',
|
||||
args: ['test.js'],
|
||||
connectionMode: 'on-demand',
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const serverInfos = await initializeClientsFromSettings(true);
|
||||
|
||||
expect(serverInfos).toHaveLength(1);
|
||||
expect(serverInfos[0].status).toBe('disconnected');
|
||||
expect(serverInfos[0].error).toContain('Failed to initialize');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tool Invocation with On-Demand Servers', () => {
|
||||
beforeEach(async () => {
|
||||
// Set up server infos with an on-demand server that's disconnected
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'on-demand-server',
|
||||
command: 'node',
|
||||
args: ['test.js'],
|
||||
connectionMode: 'on-demand',
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
// Initialize to get the server set up
|
||||
await initializeClientsFromSettings(true);
|
||||
|
||||
// Clear mocks after initialization
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Reset mock implementations
|
||||
mockClient.connect.mockResolvedValue(undefined);
|
||||
mockClient.listTools.mockResolvedValue({
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'Test tool',
|
||||
inputSchema: { type: 'object' },
|
||||
},
|
||||
],
|
||||
});
|
||||
mockClient.callTool.mockResolvedValue({
|
||||
content: [{ type: 'text', text: 'Success' }],
|
||||
});
|
||||
});
|
||||
|
||||
it('should connect on-demand server before tool invocation', async () => {
|
||||
const request = {
|
||||
params: {
|
||||
name: 'on-demand-server-test-tool',
|
||||
arguments: { arg1: 'value1' },
|
||||
},
|
||||
};
|
||||
|
||||
await handleCallToolRequest(request, {});
|
||||
|
||||
// Should connect before calling the tool
|
||||
expect(mockClient.connect).toHaveBeenCalledTimes(1);
|
||||
expect(mockClient.callTool).toHaveBeenCalledWith(
|
||||
{
|
||||
name: 'test-tool',
|
||||
arguments: { arg1: 'value1' },
|
||||
},
|
||||
undefined,
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
it('should disconnect on-demand server after tool invocation', async () => {
|
||||
const request = {
|
||||
params: {
|
||||
name: 'on-demand-server-test-tool',
|
||||
arguments: {},
|
||||
},
|
||||
};
|
||||
|
||||
await handleCallToolRequest(request, {});
|
||||
|
||||
// Should disconnect after calling the tool
|
||||
expect(mockTransport.close).toHaveBeenCalledTimes(1);
|
||||
expect(mockClient.close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should disconnect on-demand server even if tool invocation fails', async () => {
|
||||
mockClient.callTool.mockRejectedValueOnce(new Error('Tool execution failed'));
|
||||
|
||||
const request = {
|
||||
params: {
|
||||
name: 'on-demand-server-test-tool',
|
||||
arguments: {},
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await handleCallToolRequest(request, {});
|
||||
} catch (error) {
|
||||
// Expected to fail
|
||||
}
|
||||
|
||||
// Should still disconnect after error
|
||||
expect(mockTransport.close).toHaveBeenCalledTimes(1);
|
||||
expect(mockClient.close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should return error for call_tool if server not found', async () => {
|
||||
const request = {
|
||||
params: {
|
||||
name: 'call_tool',
|
||||
arguments: {
|
||||
toolName: 'nonexistent-server-tool',
|
||||
arguments: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await handleCallToolRequest(request, {});
|
||||
|
||||
expect(result.isError).toBe(true);
|
||||
expect(result.content[0].text).toContain('No available servers found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mixed Server Modes', () => {
|
||||
it('should handle both persistent and on-demand servers together', async () => {
|
||||
mockServerDao.findAll.mockResolvedValue([
|
||||
{
|
||||
name: 'persistent-server',
|
||||
command: 'node',
|
||||
args: ['persistent.js'],
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'on-demand-server',
|
||||
command: 'node',
|
||||
args: ['on-demand.js'],
|
||||
connectionMode: 'on-demand',
|
||||
enabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const serverInfos = await initializeClientsFromSettings(true);
|
||||
|
||||
expect(serverInfos).toHaveLength(2);
|
||||
|
||||
const persistentServer = serverInfos.find(s => s.name === 'persistent-server');
|
||||
const onDemandServer = serverInfos.find(s => s.name === 'on-demand-server');
|
||||
|
||||
expect(persistentServer?.connectionMode).toBe('persistent');
|
||||
expect(onDemandServer?.connectionMode).toBe('on-demand');
|
||||
expect(onDemandServer?.status).toBe('disconnected');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user