import { getTranslations, setRequestLocale } from 'next-intl/server'; import { Header } from '@/components/Header'; import { Footer } from '@/components/Footer'; import { ApiEndpointSection } from '@/components/ApiEndpointSection'; import type { EndpointDef } from '@/components/ApiEndpointSection'; import Link from 'next/link'; import { ArrowLeft, ArrowRight, Search, FileCode, Users, Compass, Mail } from 'lucide-react'; export default async function ApiDocsPage({ params, }: { params: Promise<{ locale: string }>; }) { const { locale } = await params; setRequestLocale(locale); const t = await getTranslations('docs'); const isRTL = locale === 'fa'; const ArrowIcon = isRTL ? ArrowLeft : ArrowRight; const siteUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://skills.palebluedot.live'; const labels = { parameters: t('api.labels.parameters'), requestBody: t('api.labels.requestBody'), required: t('api.labels.required'), optional: t('api.labels.optional'), default: t('api.labels.default'), responseExample: t('api.labels.responseExample'), rateLimit: t('api.labels.rateLimit'), cache: t('api.labels.cache'), authRequired: t('api.labels.authRequired'), notes: t('api.labels.notes'), }; // --- Section 1: Skills --- const skillsEndpoints: EndpointDef[] = [ { method: 'GET', path: '/api/skills', description: t('api.endpoints.searchSkills'), auth: false, rateLimit: '60 req/min', cacheTTL: '5 min', params: [ { name: 'q', type: 'string', required: false, description: t('api.params.q') }, { name: 'category', type: 'string', required: false, description: t('api.params.category') }, { name: 'platform', type: 'string', required: false, description: t('api.params.platform') + ' (claude, codex, copilot, cursor, windsurf)' }, { name: 'format', type: 'string', required: false, description: t('api.params.format'), default: 'skill.md' }, { name: 'verified', type: 'boolean', required: false, description: t('api.params.verified') }, { name: 'minStars', type: 'number', required: false, description: t('api.params.minStars') }, { name: 'sort', type: 'string', required: false, description: t('api.params.sort') + ' (stars, downloads, rating, recent)', default: 'downloads' }, { name: 'page', type: 'number', required: false, description: t('api.params.page'), default: '1' }, { name: 'limit', type: 'number', required: false, description: t('api.params.limit'), default: '20' }, ], responseExample: `{ "skills": [ { "id": "anthropic/skills/code-review", "name": "code-review", "description": "AI-powered code review assistant", "githubOwner": "anthropic", "githubRepo": "skills", "githubStars": 1234, "downloadCount": 567, "securityStatus": "PASS", "rating": 4.5, "ratingCount": 23, "isVerified": true, "compatibility": { "platforms": ["claude", "cursor"] } } ], "pagination": { "page": 1, "limit": 20, "total": 150, "totalPages": 8 }, "searchEngine": "meilisearch" }`, notes: t('api.notes.searchFallback'), }, { method: 'GET', path: '/api/skills/:id', description: t('api.endpoints.getSkill'), auth: false, rateLimit: '120 req/min', responseExample: `{ "id": "anthropic/skills/code-review", "name": "code-review", "description": "AI-powered code review assistant", "githubOwner": "anthropic", "githubRepo": "skills", "skillPath": "code-review", "branch": "main", "version": "1.0.0", "license": "MIT", "githubStars": 1234, "downloadCount": 567, "securityScore": 95, "securityStatus": "PASS", "isVerified": true, "compatibility": { "platforms": ["claude"] }, "rawContent": "# Code Review\\n...", "sourceFormat": "skill.md" }`, notes: t('api.notes.viewCount'), }, { method: 'GET', path: '/api/skills/featured', description: t('api.endpoints.featuredSkills'), auth: false, rateLimit: '120 req/min', cacheTTL: '2 hours', params: [ { name: 'limit', type: 'number', required: false, description: t('api.params.limitNum'), default: '6' }, ], }, { method: 'GET', path: '/api/skills/recent', description: t('api.endpoints.recentSkills'), auth: false, rateLimit: '120 req/min', cacheTTL: '1 hour', params: [ { name: 'limit', type: 'number', required: false, description: t('api.params.limitNum'), default: '10' }, ], }, { method: 'POST', path: '/api/skills/install', description: t('api.endpoints.trackInstall'), auth: false, bodyParams: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, { name: 'platform', type: 'string', required: false, description: t('api.params.platform') }, { name: 'method', type: 'string', required: false, description: t('api.params.method') }, ], responseExample: `{ "success": true, "skillId": "owner/repo/skill", "platform": "claude", "method": "cli" }`, notes: t('api.notes.installDedup'), }, { method: 'POST', path: '/api/skills/add-request', description: t('api.endpoints.addRequest'), auth: true, bodyParams: [ { name: 'repositoryUrl', type: 'string', required: true, description: t('api.params.repositoryUrl') }, { name: 'reason', type: 'string', required: false, description: t('api.params.reason') }, ], responseExample: `{ "success": true, "requestId": "uuid", "hasSkillMd": true, "skillCount": 3 }`, }, { method: 'POST', path: '/api/skills/removal-request', description: t('api.endpoints.removalRequest'), auth: true, bodyParams: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, { name: 'reason', type: 'string', required: false, description: t('api.params.reason') }, ], responseExample: `{ "success": true, "requestId": "uuid", "blocked": true }`, }, ]; // --- Section 2: Skill Files --- const skillFilesEndpoints: EndpointDef[] = [ { method: 'GET', path: '/api/skill-files', description: t('api.endpoints.getSkillFiles'), auth: false, rateLimit: '60 req/min', params: [ { name: 'id', type: 'string', required: true, description: t('api.params.skillId') }, ], responseExample: `{ "skillId": "owner/repo/skill", "githubOwner": "owner", "githubRepo": "repo", "skillPath": "skill", "branch": "main", "files": [ { "name": "SKILL.md", "path": "SKILL.md", "type": "file", "size": 2048, "content": "# Skill Name\\n..." } ], "fromCache": true, "cachedAt": "2026-01-15T10:30:00Z" }`, notes: t('api.notes.cacheInDB'), }, { method: 'GET', path: '/api/skill-files/zip', description: t('api.endpoints.downloadZip'), auth: false, rateLimit: '60 req/min', params: [ { name: 'id', type: 'string', required: true, description: t('api.params.skillId') }, { name: 'platform', type: 'string', required: false, description: t('api.params.platformZip'), default: 'claude' }, ], notes: t('api.notes.zipTransform'), }, ]; // --- Section 3: User Actions --- const userActionsEndpoints: EndpointDef[] = [ { method: 'GET', path: '/api/ratings', description: t('api.endpoints.getRatings'), auth: false, rateLimit: '120 req/min', params: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, { name: 'limit', type: 'number', required: false, description: t('api.params.limitNum'), default: '10' }, { name: 'offset', type: 'number', required: false, description: t('api.params.offset'), default: '0' }, ], responseExample: `{ "ratings": [ { "id": "uuid", "rating": 5, "review": "Great skill!", "createdAt": "2026-01-10T00:00:00Z", "user": { "id": "uid", "username": "user1", "avatarUrl": "https://..." } } ], "summary": { "average": 4.5, "count": 23 } }`, }, { method: 'POST', path: '/api/ratings', description: t('api.endpoints.createRating'), auth: true, rateLimit: '600 req/min', bodyParams: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, { name: 'rating', type: 'number', required: true, description: t('api.params.rating') }, { name: 'review', type: 'string', required: false, description: t('api.params.review') }, ], responseExample: `{ "rating": { "id": "uuid", "rating": 5, "review": "..." }, "summary": { "average": 4.5, "count": 24 } }`, }, { method: 'GET', path: '/api/ratings/me', description: t('api.endpoints.getMyRating'), auth: true, rateLimit: '600 req/min', params: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, ], responseExample: `{ "rating": { "id": "uuid", "rating": 5, "review": "Great!" } }`, }, { method: 'GET', path: '/api/favorites', description: t('api.endpoints.getFavorites'), auth: true, rateLimit: '600 req/min', responseExample: `{ "favorites": [ { "id": "owner/repo/skill", "name": "skill-name", "description": "...", "githubStars": 100, "downloadCount": 50, "securityStatus": "PASS", "isVerified": true, "rating": 4.5, "ratingCount": 10 } ] }`, }, { method: 'POST', path: '/api/favorites', description: t('api.endpoints.addFavorite'), auth: true, rateLimit: '600 req/min', bodyParams: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, ], responseExample: `{ "success": true, "favorited": true }`, }, { method: 'DELETE', path: '/api/favorites', description: t('api.endpoints.removeFavorite'), auth: true, rateLimit: '600 req/min', bodyParams: [ { name: 'skillId', type: 'string', required: true, description: t('api.params.skillId') }, ], responseExample: `{ "success": true, "favorited": false }`, }, { method: 'POST', path: '/api/favorites/check', description: t('api.endpoints.checkFavorites'), auth: true, rateLimit: '600 req/min', bodyParams: [ { name: 'skillIds', type: 'string[]', required: true, description: t('api.params.skillIds') }, ], responseExample: `{ "favorited": { "owner/repo/skill-a": true, "owner/repo/skill-b": false } }`, }, ]; // --- Section 4: Discovery & Metadata --- const discoveryEndpoints: EndpointDef[] = [ { method: 'GET', path: '/api/categories', description: t('api.endpoints.getCategories'), auth: false, rateLimit: '120 req/min', cacheTTL: '12 hours', responseExample: `{ "categories": [ { "id": "cat-id", "name": "Code Quality", "slug": "code-quality", "description": "...", "icon": "🔍", "skillCount": 15, "sortOrder": 1 } ] }`, }, { method: 'GET', path: '/api/stats', description: t('api.endpoints.getStats'), auth: false, rateLimit: '120 req/min', cacheTTL: '1 hour', responseExample: `{ "totalSkills": 850, "totalDownloads": 12500, "totalCategories": 23, "totalContributors": 320, "platforms": 5 }`, }, { method: 'GET', path: '/api/health', description: t('api.endpoints.healthCheck'), auth: false, responseExample: `{ "status": "healthy", "timestamp": "2026-02-11T12:00:00Z", "version": "0.2.4", "isPrimary": true, "services": { "database": { "status": "healthy", "latency": 5 }, "meilisearch": { "status": "healthy", "latency": 12 }, "redis": { "status": "healthy", "latency": 3 } } }`, }, { method: 'GET', path: '/api/attribution', description: t('api.endpoints.getAttribution'), auth: false, rateLimit: '120 req/min', cacheTTL: '1 hour', responseExample: `{ "totalSkills": 850, "totalContributors": 320, "totalRepos": 150, "licenseDistribution": [ { "license": "MIT", "count": 50, "percentage": 50 } ], "lastUpdated": "2026-02-11T00:00:00Z" }`, }, ]; // --- Section 5: Newsletter --- const newsletterEndpoints: EndpointDef[] = [ { method: 'POST', path: '/api/newsletter/subscribe', description: t('api.endpoints.subscribe'), auth: false, rateLimit: '60 req/min', bodyParams: [ { name: 'email', type: 'string', required: true, description: t('api.params.email') }, { name: 'source', type: 'string', required: false, description: t('api.params.source') }, { name: 'locale', type: 'string', required: false, description: t('api.params.locale'), default: 'en' }, ], responseExample: `{ "success": true, "subscribed": true }`, }, { method: 'POST', path: '/api/newsletter/unsubscribe', description: t('api.endpoints.unsubscribe'), auth: false, rateLimit: '60 req/min', bodyParams: [ { name: 'email', type: 'string', required: true, description: t('api.params.email') }, ], responseExample: `{ "success": true, "unsubscribed": true }`, notes: t('api.notes.alwaysSuccess'), }, ]; const sections = [ { title: t('api.sections.skills.title'), description: t('api.sections.skills.description'), icon: Search, endpoints: skillsEndpoints }, { title: t('api.sections.skillFiles.title'), description: t('api.sections.skillFiles.description'), icon: FileCode, endpoints: skillFilesEndpoints }, { title: t('api.sections.userActions.title'), description: t('api.sections.userActions.description'), icon: Users, endpoints: userActionsEndpoints }, { title: t('api.sections.discovery.title'), description: t('api.sections.discovery.description'), icon: Compass, endpoints: discoveryEndpoints }, { title: t('api.sections.newsletter.title'), description: t('api.sections.newsletter.description'), icon: Mail, endpoints: newsletterEndpoints }, ]; return (
{t('title')}

{t('api.title')}

{t('api.description')}

{/* Base URL */}

{t('api.baseUrl')}

{siteUrl}
{/* Authentication */}

{t('api.authSection.title')}

{t('api.authSection.description')}

{t('api.authSection.howTo')}

{/* Rate Limiting */}

{t('api.rateLimitSection.title')}

{t('api.rateLimitSection.description')}

{t('api.rateLimitSection.tier')} {t('api.rateLimitSection.limit')} {t('api.rateLimitSection.use')}
{t('api.rateLimitSection.anonymous')} 120 req/min {t('api.rateLimitSection.anonymousUse')}
{t('api.rateLimitSection.search')} 60 req/min {t('api.rateLimitSection.searchUse')}
{t('api.rateLimitSection.authenticated')} 600 req/min {t('api.rateLimitSection.authenticatedUse')}

{t('api.rateLimitSection.headersTitle')}

X-RateLimit-Limit — {t('api.rateLimitSection.headerLimit')}

X-RateLimit-Remaining — {t('api.rateLimitSection.headerRemaining')}

X-RateLimit-Reset — {t('api.rateLimitSection.headerReset')}

{/* Error Responses */}

{t('api.errorSection.title')}

{t('api.errorSection.description')}

{`{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded",
  "retryAfter": 45,
  "limit": 60
}`}

{t('api.errorSection.commonCodes')}

400 — {t('api.errorSection.code400')}

401 — {t('api.errorSection.code401')}

404 — {t('api.errorSection.code404')}

429 — {t('api.errorSection.code429')}

500 — {t('api.errorSection.code500')}

{/* Quick example */}

Quick Example

{`curl "${siteUrl}/api/skills?q=code-review&limit=5"`}

{/* Endpoint Sections */} {sections.map((section, index) => ( ))}
); }