Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
145 lines
3.9 KiB
TypeScript
145 lines
3.9 KiB
TypeScript
/**
|
|
* DSS API Client
|
|
*
|
|
* Communicates with the DSS server.
|
|
*/
|
|
|
|
import { getConfig } from './config.js';
|
|
|
|
export interface ApiOptions {
|
|
port?: number;
|
|
baseUrl?: string;
|
|
}
|
|
|
|
export class DSSApiClient {
|
|
private baseUrl: string;
|
|
|
|
constructor(options: ApiOptions = {}) {
|
|
const config = getConfig();
|
|
const port = options.port || config.port || 3456;
|
|
this.baseUrl = options.baseUrl || `http://localhost:${port}/api`;
|
|
}
|
|
|
|
private async request<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const url = `${this.baseUrl}${endpoint}`;
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options.headers,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({ message: response.statusText })) as { message?: string };
|
|
throw new Error(errorData.message || `Request failed: ${response.status}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
return text ? JSON.parse(text) as T : {} as T;
|
|
}
|
|
|
|
async health(): Promise<{ status: string; figma_mode: string }> {
|
|
// Health endpoint is at root, not under /api
|
|
const url = this.baseUrl.replace('/api', '') + '/health';
|
|
const response = await fetch(url);
|
|
return response.json() as Promise<{ status: string; figma_mode: string }>;
|
|
}
|
|
|
|
async getConfig(): Promise<Record<string, unknown>> {
|
|
return this.request('/config');
|
|
}
|
|
|
|
async setFigmaToken(token: string): Promise<void> {
|
|
await this.request('/config', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ figma_token: token }),
|
|
});
|
|
}
|
|
|
|
async testFigmaConnection(): Promise<{ success: boolean; user?: string; error?: string }> {
|
|
return this.request('/config/figma/test', { method: 'POST' });
|
|
}
|
|
|
|
async extractTokens(fileKey: string, format: string = 'css'): Promise<{
|
|
success: boolean;
|
|
tokens_count: number;
|
|
tokens: Array<{ name: string; value: string; type: string; category: string }>;
|
|
formatted_output: string;
|
|
output_path: string;
|
|
}> {
|
|
return this.request('/figma/extract-variables', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ file_key: fileKey, format }),
|
|
});
|
|
}
|
|
|
|
async extractComponents(fileKey: string): Promise<{
|
|
success: boolean;
|
|
components_count: number;
|
|
components: Array<{ name: string; key: string; description: string; variants: string[] }>;
|
|
output_path: string;
|
|
}> {
|
|
return this.request('/figma/extract-components', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ file_key: fileKey }),
|
|
});
|
|
}
|
|
|
|
async syncTokens(fileKey: string, targetPath: string, format: string = 'css'): Promise<{
|
|
success: boolean;
|
|
tokens_synced: number;
|
|
output_file: string;
|
|
}> {
|
|
return this.request('/figma/sync-tokens', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ file_key: fileKey, target_path: targetPath, format }),
|
|
});
|
|
}
|
|
|
|
async generateCode(fileKey: string, componentName: string, framework: string = 'react'): Promise<{
|
|
success: boolean;
|
|
component: string;
|
|
framework: string;
|
|
code: string;
|
|
}> {
|
|
return this.request('/figma/generate-code', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ file_key: fileKey, component_name: componentName, framework }),
|
|
});
|
|
}
|
|
|
|
async getProjects(): Promise<Array<{
|
|
id: string;
|
|
name: string;
|
|
figma_file_key: string;
|
|
status: string;
|
|
}>> {
|
|
return this.request('/projects');
|
|
}
|
|
|
|
async createProject(data: {
|
|
name: string;
|
|
description?: string;
|
|
figma_file_key?: string;
|
|
}): Promise<{ id: string; name: string }> {
|
|
return this.request('/projects', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
let apiClient: DSSApiClient | null = null;
|
|
|
|
export function getApiClient(options?: ApiOptions): DSSApiClient {
|
|
if (!apiClient || options) {
|
|
apiClient = new DSSApiClient(options);
|
|
}
|
|
return apiClient;
|
|
}
|