✨ Features: - Modern SaaS automation platform - Next.js 15 + TypeScript frontend - Node.js + Express backend - PostgreSQL database with full schema - Docker Compose setup - Admin panel with analytics - Template marketplace (6 templates) - Integrations hub (10+ services) - Authentication & role-based access - Responsive n8n-style design 🎯 Ready for demo and deployment 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
226 lines
No EOL
6.8 KiB
TypeScript
226 lines
No EOL
6.8 KiB
TypeScript
import axios, { AxiosInstance } from 'axios';
|
|
|
|
interface N8nConfig {
|
|
baseUrl: string;
|
|
apiToken: string;
|
|
}
|
|
|
|
interface WorkflowData {
|
|
name: string;
|
|
active: boolean;
|
|
nodes: any[];
|
|
connections: any;
|
|
settings?: any;
|
|
staticData?: any;
|
|
}
|
|
|
|
interface N8nWorkflow {
|
|
id: string;
|
|
name: string;
|
|
active: boolean;
|
|
nodes: any[];
|
|
connections: any;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
settings?: any;
|
|
staticData?: any;
|
|
}
|
|
|
|
interface ExecutionResult {
|
|
id: string;
|
|
finished: boolean;
|
|
mode: string;
|
|
startedAt: string;
|
|
stoppedAt?: string;
|
|
workflowData: any;
|
|
data?: any;
|
|
}
|
|
|
|
class N8nService {
|
|
private client: AxiosInstance;
|
|
private config: N8nConfig;
|
|
|
|
constructor(config: N8nConfig) {
|
|
this.config = config;
|
|
this.client = axios.create({
|
|
baseURL: `${config.baseUrl}/api/v1`,
|
|
headers: {
|
|
'X-N8N-API-KEY': config.apiToken,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
timeout: 30000,
|
|
});
|
|
|
|
// Add response interceptor for error handling
|
|
this.client.interceptors.response.use(
|
|
response => response,
|
|
error => {
|
|
console.error('N8n API Error:', error.response?.data || error.message);
|
|
throw error;
|
|
}
|
|
);
|
|
}
|
|
|
|
// Workflow Management
|
|
async getWorkflows(): Promise<N8nWorkflow[]> {
|
|
try {
|
|
const response = await this.client.get('/workflows');
|
|
return response.data.data || response.data;
|
|
} catch (error) {
|
|
console.error('Failed to fetch workflows:', error);
|
|
throw new Error('Failed to fetch workflows from n8n');
|
|
}
|
|
}
|
|
|
|
async getWorkflow(workflowId: string): Promise<N8nWorkflow> {
|
|
try {
|
|
const response = await this.client.get(`/workflows/${workflowId}`);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to fetch workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to fetch workflow ${workflowId} from n8n`);
|
|
}
|
|
}
|
|
|
|
async createWorkflow(workflowData: WorkflowData): Promise<N8nWorkflow> {
|
|
try {
|
|
const response = await this.client.post('/workflows', workflowData);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to create workflow:', error);
|
|
throw new Error('Failed to create workflow in n8n');
|
|
}
|
|
}
|
|
|
|
async updateWorkflow(workflowId: string, workflowData: Partial<WorkflowData>): Promise<N8nWorkflow> {
|
|
try {
|
|
const response = await this.client.patch(`/workflows/${workflowId}`, workflowData);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to update workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to update workflow ${workflowId} in n8n`);
|
|
}
|
|
}
|
|
|
|
async deleteWorkflow(workflowId: string): Promise<void> {
|
|
try {
|
|
await this.client.delete(`/workflows/${workflowId}`);
|
|
} catch (error) {
|
|
console.error(`Failed to delete workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to delete workflow ${workflowId} from n8n`);
|
|
}
|
|
}
|
|
|
|
async activateWorkflow(workflowId: string): Promise<N8nWorkflow> {
|
|
try {
|
|
const response = await this.client.patch(`/workflows/${workflowId}`, { active: true });
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to activate workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to activate workflow ${workflowId} in n8n`);
|
|
}
|
|
}
|
|
|
|
async deactivateWorkflow(workflowId: string): Promise<N8nWorkflow> {
|
|
try {
|
|
const response = await this.client.patch(`/workflows/${workflowId}`, { active: false });
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to deactivate workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to deactivate workflow ${workflowId} in n8n`);
|
|
}
|
|
}
|
|
|
|
// Execution Management
|
|
async executeWorkflow(workflowId: string, inputData?: any): Promise<ExecutionResult> {
|
|
try {
|
|
const response = await this.client.post(`/workflows/${workflowId}/execute`, {
|
|
...(inputData && { inputData })
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to execute workflow ${workflowId}:`, error);
|
|
throw new Error(`Failed to execute workflow ${workflowId} in n8n`);
|
|
}
|
|
}
|
|
|
|
async getExecutions(workflowId?: string, limit: number = 20): Promise<ExecutionResult[]> {
|
|
try {
|
|
const params: any = { limit };
|
|
if (workflowId) {
|
|
params.workflowId = workflowId;
|
|
}
|
|
|
|
const response = await this.client.get('/executions', { params });
|
|
return response.data.data || response.data;
|
|
} catch (error) {
|
|
console.error('Failed to fetch executions:', error);
|
|
throw new Error('Failed to fetch executions from n8n');
|
|
}
|
|
}
|
|
|
|
async getExecution(executionId: string): Promise<ExecutionResult> {
|
|
try {
|
|
const response = await this.client.get(`/executions/${executionId}`);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Failed to fetch execution ${executionId}:`, error);
|
|
throw new Error(`Failed to fetch execution ${executionId} from n8n`);
|
|
}
|
|
}
|
|
|
|
async deleteExecution(executionId: string): Promise<void> {
|
|
try {
|
|
await this.client.delete(`/executions/${executionId}`);
|
|
} catch (error) {
|
|
console.error(`Failed to delete execution ${executionId}:`, error);
|
|
throw new Error(`Failed to delete execution ${executionId} from n8n`);
|
|
}
|
|
}
|
|
|
|
// Health and Status
|
|
async getHealth(): Promise<{ status: string }> {
|
|
try {
|
|
const response = await this.client.get('/health');
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to check n8n health:', error);
|
|
throw new Error('Failed to check n8n health');
|
|
}
|
|
}
|
|
|
|
// Credentials Management (if needed)
|
|
async getCredentials(): Promise<any[]> {
|
|
try {
|
|
const response = await this.client.get('/credentials');
|
|
return response.data.data || response.data;
|
|
} catch (error) {
|
|
console.error('Failed to fetch credentials:', error);
|
|
throw new Error('Failed to fetch credentials from n8n');
|
|
}
|
|
}
|
|
|
|
// Test connection
|
|
async testConnection(): Promise<boolean> {
|
|
try {
|
|
await this.getHealth();
|
|
return true;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Factory function to create n8n service instance
|
|
export const createN8nService = (config: N8nConfig): N8nService => {
|
|
return new N8nService(config);
|
|
};
|
|
|
|
// Default instance using environment variables
|
|
export const n8nService = createN8nService({
|
|
baseUrl: process.env.N8N_BASE_URL || 'https://bot.ai-impress.com',
|
|
apiToken: process.env.N8N_API_TOKEN || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1OWQyN2Q0ZS1jNTU3LTQxMDUtYjZmMy05Y2JmM2U5MzU1NWUiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzU5MDc1NDI4fQ.HCnDOPdq8GcphuPpz1o9871VOLbpMvd7m8C47e2Kq50',
|
|
});
|
|
|
|
export default n8nService;
|
|
export type { N8nWorkflow, WorkflowData, ExecutionResult, N8nConfig }; |