Files
patchy631--ai-engineering-hub/open-agent-builder/app/api/workflows/route.ts
T
2026-07-13 12:37:47 +08:00

213 lines
5.7 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { getConvexClient, getAuthenticatedConvexClient, api, isConvexConfigured } from '@/lib/convex/client';
export const dynamic = 'force-dynamic';
/**
* GET /api/workflows - List all workflows
* Uses Convex for storage
*/
export async function GET(request: NextRequest) {
try {
if (!isConvexConfigured()) {
return NextResponse.json({
workflows: [],
total: 0,
source: 'none',
message: 'Convex not configured. Add NEXT_PUBLIC_CONVEX_URL to .env.local',
});
}
const convex = await getAuthenticatedConvexClient();
const workflows = await convex.query(api.workflows.listWorkflows, {});
return NextResponse.json({
workflows: workflows.map((w: any) => ({
id: w.customId || w._id, // Use customId if exists, otherwise Convex ID
name: w.name,
description: w.description,
category: w.category,
tags: w.tags,
difficulty: w.difficulty,
estimatedTime: w.estimatedTime,
nodes: w.nodes,
edges: w.edges,
createdAt: w.createdAt,
updatedAt: w.updatedAt,
nodeCount: w.nodes?.length || 0,
edgeCount: w.edges?.length || 0,
})),
total: workflows.length,
source: 'convex',
});
} catch (error) {
console.error('Error fetching workflows:', error);
return NextResponse.json(
{
error: 'Failed to fetch workflows',
message: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
);
}
}
/**
* POST /api/workflows - Save a workflow to Convex
*/
export async function POST(request: NextRequest) {
try {
let workflow;
try {
const body = await request.text();
if (!body || body.trim() === '') {
return NextResponse.json(
{ error: 'Request body is empty' },
{ status: 400 }
);
}
workflow = JSON.parse(body);
} catch (parseError) {
console.error('JSON parse error:', parseError);
return NextResponse.json(
{ error: 'Invalid JSON in request body' },
{ status: 400 }
);
}
if (!workflow.id && !workflow.name) {
return NextResponse.json(
{ error: 'Workflow must have either id or name' },
{ status: 400 }
);
}
if (!isConvexConfigured()) {
return NextResponse.json({
success: false,
message: 'Convex not configured. Add NEXT_PUBLIC_CONVEX_URL to .env.local',
}, { status: 500 });
}
// Validate workflow has required fields
if (!workflow.nodes || !Array.isArray(workflow.nodes)) {
return NextResponse.json(
{ error: 'Workflow must have a nodes array' },
{ status: 400 }
);
}
if (!workflow.edges || !Array.isArray(workflow.edges)) {
return NextResponse.json(
{ error: 'Workflow must have an edges array' },
{ status: 400 }
);
}
const convex = await getAuthenticatedConvexClient();
// Use workflow.id as customId for Convex
const customId = workflow.id || `workflow_${Date.now()}`;
const savedId = await convex.mutation(api.workflows.saveWorkflow, {
customId,
name: workflow.name || 'Untitled Workflow',
description: workflow.description,
category: workflow.category,
tags: workflow.tags,
difficulty: workflow.difficulty,
estimatedTime: workflow.estimatedTime,
nodes: workflow.nodes,
edges: workflow.edges,
version: workflow.version,
isTemplate: workflow.isTemplate,
});
return NextResponse.json({
success: true,
workflowId: savedId,
source: 'convex',
message: 'Workflow saved successfully',
});
} catch (error) {
console.error('Error saving workflow:', error);
return NextResponse.json(
{
error: 'Failed to save workflow',
message: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
);
}
}
/**
* DELETE /api/workflows?id=xxx - Delete a workflow from Convex
*/
export async function DELETE(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const workflowId = searchParams.get('id');
if (!workflowId) {
return NextResponse.json(
{ error: 'Workflow ID is required' },
{ status: 400 }
);
}
if (!isConvexConfigured()) {
return NextResponse.json({
success: false,
message: 'Convex not configured',
}, { status: 500 });
}
const convex = await getAuthenticatedConvexClient();
// Look up workflow by customId first, then try Convex ID
let workflow = await convex.query(api.workflows.getWorkflowByCustomId, {
customId: workflowId,
});
// If not found and looks like Convex ID, try direct lookup
if (!workflow && workflowId.startsWith('j')) {
try {
workflow = await convex.query(api.workflows.getWorkflow, {
id: workflowId as any,
});
} catch (e) {
// Not a valid Convex ID
}
}
if (!workflow) {
return NextResponse.json(
{ error: `Workflow ${workflowId} not found` },
{ status: 404 }
);
}
// Delete using Convex ID
await convex.mutation(api.workflows.deleteWorkflow, {
id: workflow._id,
});
return NextResponse.json({
success: true,
source: 'convex',
message: 'Workflow deleted successfully',
});
} catch (error) {
console.error('Error deleting workflow:', error);
return NextResponse.json(
{
error: 'Failed to delete workflow',
message: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
);
}
}