Initial release v1.0.0

Open-source marketplace for AI Agent skills.

Features:
- Next.js 15 web app with i18n (en/fa)
- CLI tool for skill installation (npx skillhub)
- GitHub crawler/indexer with multi-strategy discovery
- Security scanning for all indexed skills
- Self-hostable with Docker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
airano
2026-02-12 06:08:51 +03:30
commit 97b427831a
227 changed files with 48411 additions and 0 deletions

71
apps/web/e2e/api.spec.ts Normal file
View File

@@ -0,0 +1,71 @@
import { test, expect } from '@playwright/test';
test.describe('API Health Checks', () => {
test('health endpoint should return OK', async ({ request }) => {
const response = await request.get('/api/health');
expect(response.status()).toBe(200);
const data = await response.json();
// Health endpoint returns 'healthy', 'degraded', or 'unhealthy'
expect(['healthy', 'degraded', 'unhealthy']).toContain(data.status);
});
test('stats endpoint should return stats', async ({ request }) => {
const response = await request.get('/api/stats');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data).toHaveProperty('totalSkills');
expect(data).toHaveProperty('totalDownloads');
expect(data).toHaveProperty('totalCategories');
});
test('categories endpoint should return categories', async ({ request }) => {
const response = await request.get('/api/categories');
expect(response.status()).toBe(200);
const data = await response.json();
// API returns { categories: [...] }
expect(data).toHaveProperty('categories');
expect(Array.isArray(data.categories)).toBe(true);
});
test('skills endpoint should return skills list', async ({ request }) => {
const response = await request.get('/api/skills');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data).toHaveProperty('skills');
expect(data).toHaveProperty('pagination');
expect(Array.isArray(data.skills)).toBe(true);
});
test('skills endpoint should support search query', async ({ request }) => {
const response = await request.get('/api/skills?q=test');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data).toHaveProperty('skills');
});
test('skills endpoint should support pagination', async ({ request }) => {
const response = await request.get('/api/skills?page=1&limit=5');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data.pagination.page).toBe(1);
expect(data.pagination.limit).toBe(5);
});
test('featured skills endpoint should return featured skills', async ({ request }) => {
const response = await request.get('/api/skills/featured');
expect(response.status()).toBe(200);
const data = await response.json();
// API returns { skills: [...] }
expect(data).toHaveProperty('skills');
expect(Array.isArray(data.skills)).toBe(true);
});
test('recent skills endpoint should return recent skills', async ({ request }) => {
const response = await request.get('/api/skills/recent');
expect(response.status()).toBe(200);
const data = await response.json();
// API returns { skills: [...] }
expect(data).toHaveProperty('skills');
expect(Array.isArray(data.skills)).toBe(true);
});
});