@d34dman/flowdrop 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +293 -0
- package/dist/adapters/WorkflowAdapter.d.ts +166 -0
- package/dist/adapters/WorkflowAdapter.js +337 -0
- package/dist/api/client.d.ts +79 -0
- package/dist/api/client.js +208 -0
- package/dist/app.css +0 -0
- package/dist/clients/ApiClient.d.ts +203 -0
- package/dist/clients/ApiClient.js +212 -0
- package/dist/components/App.svelte +237 -0
- package/dist/components/App.svelte.d.ts +3 -0
- package/dist/components/CanvasBanner.svelte +51 -0
- package/dist/components/CanvasBanner.svelte.d.ts +22 -0
- package/dist/components/LoadingSpinner.svelte +36 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +8 -0
- package/dist/components/Node.svelte +38 -0
- package/dist/components/Node.svelte.d.ts +4 -0
- package/dist/components/NodeSidebar.svelte +500 -0
- package/dist/components/NodeSidebar.svelte.d.ts +9 -0
- package/dist/components/WorkflowEditor.svelte +542 -0
- package/dist/components/WorkflowEditor.svelte.d.ts +10 -0
- package/dist/components/WorkflowNode.svelte +558 -0
- package/dist/components/WorkflowNode.svelte.d.ts +11 -0
- package/dist/data/samples.d.ts +17 -0
- package/dist/data/samples.js +1193 -0
- package/dist/examples/adapter-usage.d.ts +66 -0
- package/dist/examples/adapter-usage.js +138 -0
- package/dist/examples/api-client-usage.d.ts +31 -0
- package/dist/examples/api-client-usage.js +241 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +27 -0
- package/dist/services/api.d.ts +110 -0
- package/dist/services/api.js +149 -0
- package/dist/services/workflowStorage.d.ts +37 -0
- package/dist/services/workflowStorage.js +116 -0
- package/dist/styles/base.css +858 -0
- package/dist/svelte-app.d.ts +17 -0
- package/dist/svelte-app.js +30 -0
- package/dist/types/index.d.ts +179 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/colors.d.ts +121 -0
- package/dist/utils/colors.js +240 -0
- package/dist/utils/connections.d.ts +47 -0
- package/dist/utils/connections.js +240 -0
- package/dist/utils/icons.d.ts +102 -0
- package/dist/utils/icons.js +149 -0
- package/package.json +99 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkflowAdapter - Abstracts SvelteFlow internals for external systems
|
|
3
|
+
*
|
|
4
|
+
* This adapter provides a clean interface for working with workflows without
|
|
5
|
+
* needing to understand SvelteFlow's internal structure. It handles:
|
|
6
|
+
* - Converting between standard workflow format and SvelteFlow format
|
|
7
|
+
* - CRUD operations on workflows, nodes, and edges
|
|
8
|
+
* - Validation and error checking
|
|
9
|
+
* - Import/export functionality
|
|
10
|
+
*
|
|
11
|
+
* The adapter is designed to be used by:
|
|
12
|
+
* - Backend systems that need to process workflows
|
|
13
|
+
* - External applications that want to integrate with FlowDrop
|
|
14
|
+
* - Systems that need to generate or modify workflows programmatically
|
|
15
|
+
*/
|
|
16
|
+
import { v4 as uuidv4 } from "uuid";
|
|
17
|
+
/**
|
|
18
|
+
* Workflow Adapter Class
|
|
19
|
+
* Provides a clean API for workflow operations without exposing SvelteFlow internals
|
|
20
|
+
*/
|
|
21
|
+
export class WorkflowAdapter {
|
|
22
|
+
nodeTypes = [];
|
|
23
|
+
constructor(nodeTypes = []) {
|
|
24
|
+
this.nodeTypes = nodeTypes;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new workflow
|
|
28
|
+
*/
|
|
29
|
+
createWorkflow(name, description) {
|
|
30
|
+
return {
|
|
31
|
+
id: uuidv4(),
|
|
32
|
+
name,
|
|
33
|
+
description,
|
|
34
|
+
nodes: [],
|
|
35
|
+
edges: [],
|
|
36
|
+
metadata: {
|
|
37
|
+
version: "1.0.0",
|
|
38
|
+
createdAt: new Date().toISOString(),
|
|
39
|
+
updatedAt: new Date().toISOString()
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add a node to a workflow
|
|
45
|
+
*/
|
|
46
|
+
addNode(workflow, nodeType, position, config) {
|
|
47
|
+
const metadata = this.nodeTypes.find(nt => nt.id === nodeType);
|
|
48
|
+
if (!metadata) {
|
|
49
|
+
throw new Error(`Node type '${nodeType}' not found`);
|
|
50
|
+
}
|
|
51
|
+
const node = {
|
|
52
|
+
id: uuidv4(),
|
|
53
|
+
type: nodeType,
|
|
54
|
+
position,
|
|
55
|
+
data: {
|
|
56
|
+
label: metadata.name,
|
|
57
|
+
config: config || {},
|
|
58
|
+
metadata
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
workflow.nodes.push(node);
|
|
62
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
63
|
+
return node;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Remove a node from a workflow
|
|
67
|
+
*/
|
|
68
|
+
removeNode(workflow, nodeId) {
|
|
69
|
+
const nodeIndex = workflow.nodes.findIndex(n => n.id === nodeId);
|
|
70
|
+
if (nodeIndex === -1)
|
|
71
|
+
return false;
|
|
72
|
+
workflow.nodes.splice(nodeIndex, 1);
|
|
73
|
+
// Remove associated edges
|
|
74
|
+
workflow.edges = workflow.edges.filter(edge => edge.source !== nodeId && edge.target !== nodeId);
|
|
75
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Update node position
|
|
80
|
+
*/
|
|
81
|
+
updateNodePosition(workflow, nodeId, position) {
|
|
82
|
+
const node = workflow.nodes.find(n => n.id === nodeId);
|
|
83
|
+
if (!node)
|
|
84
|
+
return false;
|
|
85
|
+
node.position = position;
|
|
86
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Update node configuration
|
|
91
|
+
*/
|
|
92
|
+
updateNodeConfig(workflow, nodeId, config) {
|
|
93
|
+
const node = workflow.nodes.find(n => n.id === nodeId);
|
|
94
|
+
if (!node)
|
|
95
|
+
return false;
|
|
96
|
+
node.data.config = { ...node.data.config, ...config };
|
|
97
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Add an edge between nodes
|
|
102
|
+
*/
|
|
103
|
+
addEdge(workflow, sourceNodeId, targetNodeId, sourceHandle, targetHandle) {
|
|
104
|
+
const edge = {
|
|
105
|
+
id: uuidv4(),
|
|
106
|
+
source: sourceNodeId,
|
|
107
|
+
target: targetNodeId,
|
|
108
|
+
sourceHandle,
|
|
109
|
+
targetHandle
|
|
110
|
+
};
|
|
111
|
+
workflow.edges.push(edge);
|
|
112
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
113
|
+
return edge;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Remove an edge from a workflow
|
|
117
|
+
*/
|
|
118
|
+
removeEdge(workflow, edgeId) {
|
|
119
|
+
const edgeIndex = workflow.edges.findIndex(e => e.id === edgeId);
|
|
120
|
+
if (edgeIndex === -1)
|
|
121
|
+
return false;
|
|
122
|
+
workflow.edges.splice(edgeIndex, 1);
|
|
123
|
+
workflow.metadata.updatedAt = new Date().toISOString();
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get all nodes of a specific type
|
|
128
|
+
*/
|
|
129
|
+
getNodesByType(workflow, nodeType) {
|
|
130
|
+
return workflow.nodes.filter(node => node.type === nodeType);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get all edges connected to a node
|
|
134
|
+
*/
|
|
135
|
+
getNodeEdges(workflow, nodeId) {
|
|
136
|
+
return workflow.edges.filter(edge => edge.source === nodeId || edge.target === nodeId);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get connected nodes (both incoming and outgoing)
|
|
140
|
+
*/
|
|
141
|
+
getConnectedNodes(workflow, nodeId) {
|
|
142
|
+
const connectedNodeIds = new Set();
|
|
143
|
+
workflow.edges.forEach(edge => {
|
|
144
|
+
if (edge.source === nodeId) {
|
|
145
|
+
connectedNodeIds.add(edge.target);
|
|
146
|
+
}
|
|
147
|
+
else if (edge.target === nodeId) {
|
|
148
|
+
connectedNodeIds.add(edge.source);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return workflow.nodes.filter(node => connectedNodeIds.has(node.id));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Validate workflow structure
|
|
155
|
+
*/
|
|
156
|
+
validateWorkflow(workflow) {
|
|
157
|
+
const errors = [];
|
|
158
|
+
const warnings = [];
|
|
159
|
+
// Check for empty workflow
|
|
160
|
+
if (workflow.nodes.length === 0) {
|
|
161
|
+
warnings.push("Workflow has no nodes");
|
|
162
|
+
}
|
|
163
|
+
// Check for orphaned edges
|
|
164
|
+
const nodeIds = new Set(workflow.nodes.map(n => n.id));
|
|
165
|
+
workflow.edges.forEach(edge => {
|
|
166
|
+
if (!nodeIds.has(edge.source)) {
|
|
167
|
+
errors.push(`Edge ${edge.id} references non-existent source node ${edge.source}`);
|
|
168
|
+
}
|
|
169
|
+
if (!nodeIds.has(edge.target)) {
|
|
170
|
+
errors.push(`Edge ${edge.id} references non-existent target node ${edge.target}`);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
// Check for self-connections
|
|
174
|
+
workflow.edges.forEach(edge => {
|
|
175
|
+
if (edge.source === edge.target) {
|
|
176
|
+
errors.push(`Node ${edge.source} cannot connect to itself`);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
// Check for duplicate node IDs
|
|
180
|
+
const nodeIdCounts = new Map();
|
|
181
|
+
workflow.nodes.forEach(node => {
|
|
182
|
+
nodeIdCounts.set(node.id, (nodeIdCounts.get(node.id) || 0) + 1);
|
|
183
|
+
});
|
|
184
|
+
nodeIdCounts.forEach((count, id) => {
|
|
185
|
+
if (count > 1) {
|
|
186
|
+
errors.push(`Duplicate node ID: ${id}`);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
// Check for duplicate edge IDs
|
|
190
|
+
const edgeIdCounts = new Map();
|
|
191
|
+
workflow.edges.forEach(edge => {
|
|
192
|
+
edgeIdCounts.set(edge.id, (edgeIdCounts.get(edge.id) || 0) + 1);
|
|
193
|
+
});
|
|
194
|
+
edgeIdCounts.forEach((count, id) => {
|
|
195
|
+
if (count > 1) {
|
|
196
|
+
errors.push(`Duplicate edge ID: ${id}`);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
valid: errors.length === 0,
|
|
201
|
+
errors,
|
|
202
|
+
warnings
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Export workflow to JSON
|
|
207
|
+
*/
|
|
208
|
+
exportWorkflow(workflow) {
|
|
209
|
+
return JSON.stringify(workflow, null, 2);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Import workflow from JSON
|
|
213
|
+
*/
|
|
214
|
+
importWorkflow(json) {
|
|
215
|
+
try {
|
|
216
|
+
const workflow = JSON.parse(json);
|
|
217
|
+
// Validate the imported workflow
|
|
218
|
+
const validation = this.validateWorkflow(workflow);
|
|
219
|
+
if (!validation.valid) {
|
|
220
|
+
throw new Error(`Invalid workflow: ${validation.errors.join(", ")}`);
|
|
221
|
+
}
|
|
222
|
+
// Update metadata
|
|
223
|
+
workflow.metadata = {
|
|
224
|
+
version: workflow.metadata?.version || "1.0.0",
|
|
225
|
+
createdAt: workflow.metadata?.createdAt || new Date().toISOString(),
|
|
226
|
+
updatedAt: new Date().toISOString(),
|
|
227
|
+
author: workflow.metadata?.author,
|
|
228
|
+
tags: workflow.metadata?.tags
|
|
229
|
+
};
|
|
230
|
+
return workflow;
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
throw new Error(`Failed to import workflow: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Convert SvelteFlow workflow to standard format
|
|
238
|
+
*/
|
|
239
|
+
fromSvelteFlow(svelteFlowWorkflow) {
|
|
240
|
+
return {
|
|
241
|
+
id: svelteFlowWorkflow.id,
|
|
242
|
+
name: svelteFlowWorkflow.name,
|
|
243
|
+
description: svelteFlowWorkflow.description,
|
|
244
|
+
nodes: svelteFlowWorkflow.nodes.map(node => ({
|
|
245
|
+
id: node.id,
|
|
246
|
+
type: node.data.metadata.id,
|
|
247
|
+
position: node.position,
|
|
248
|
+
data: {
|
|
249
|
+
label: node.data.label,
|
|
250
|
+
config: node.data.config,
|
|
251
|
+
metadata: node.data.metadata
|
|
252
|
+
}
|
|
253
|
+
})),
|
|
254
|
+
edges: svelteFlowWorkflow.edges.map(edge => ({
|
|
255
|
+
id: edge.id,
|
|
256
|
+
source: edge.source,
|
|
257
|
+
target: edge.target,
|
|
258
|
+
sourceHandle: edge.sourceHandle,
|
|
259
|
+
targetHandle: edge.targetHandle
|
|
260
|
+
})),
|
|
261
|
+
metadata: svelteFlowWorkflow.metadata
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Convert standard workflow to SvelteFlow format
|
|
266
|
+
*/
|
|
267
|
+
toSvelteFlow(workflow) {
|
|
268
|
+
return {
|
|
269
|
+
id: workflow.id,
|
|
270
|
+
name: workflow.name,
|
|
271
|
+
description: workflow.description,
|
|
272
|
+
nodes: workflow.nodes.map(node => ({
|
|
273
|
+
id: node.id,
|
|
274
|
+
type: "workflowNode",
|
|
275
|
+
position: node.position,
|
|
276
|
+
deletable: true,
|
|
277
|
+
data: {
|
|
278
|
+
label: node.data.label,
|
|
279
|
+
config: node.data.config,
|
|
280
|
+
metadata: node.data.metadata,
|
|
281
|
+
nodeId: node.id
|
|
282
|
+
}
|
|
283
|
+
})),
|
|
284
|
+
edges: workflow.edges.map(edge => ({
|
|
285
|
+
id: edge.id,
|
|
286
|
+
source: edge.source,
|
|
287
|
+
target: edge.target,
|
|
288
|
+
sourceHandle: edge.sourceHandle,
|
|
289
|
+
targetHandle: edge.targetHandle
|
|
290
|
+
})),
|
|
291
|
+
metadata: workflow.metadata
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Get workflow statistics
|
|
296
|
+
*/
|
|
297
|
+
getWorkflowStats(workflow) {
|
|
298
|
+
const nodeTypeCounts = new Map();
|
|
299
|
+
workflow.nodes.forEach(node => {
|
|
300
|
+
nodeTypeCounts.set(node.type, (nodeTypeCounts.get(node.type) || 0) + 1);
|
|
301
|
+
});
|
|
302
|
+
return {
|
|
303
|
+
totalNodes: workflow.nodes.length,
|
|
304
|
+
totalEdges: workflow.edges.length,
|
|
305
|
+
nodeTypeCounts: Object.fromEntries(nodeTypeCounts),
|
|
306
|
+
lastModified: workflow.metadata?.updatedAt
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Clone a workflow
|
|
311
|
+
*/
|
|
312
|
+
cloneWorkflow(workflow, newName) {
|
|
313
|
+
const cloned = JSON.parse(JSON.stringify(workflow));
|
|
314
|
+
// Generate new IDs for all nodes and edges
|
|
315
|
+
const idMapping = new Map();
|
|
316
|
+
cloned.nodes.forEach(node => {
|
|
317
|
+
const oldId = node.id;
|
|
318
|
+
node.id = uuidv4();
|
|
319
|
+
idMapping.set(oldId, node.id);
|
|
320
|
+
});
|
|
321
|
+
cloned.edges.forEach(edge => {
|
|
322
|
+
edge.id = uuidv4();
|
|
323
|
+
edge.source = idMapping.get(edge.source) || edge.source;
|
|
324
|
+
edge.target = idMapping.get(edge.target) || edge.target;
|
|
325
|
+
});
|
|
326
|
+
cloned.id = uuidv4();
|
|
327
|
+
cloned.name = newName || `${workflow.name} (Copy)`;
|
|
328
|
+
cloned.metadata = {
|
|
329
|
+
version: cloned.metadata?.version || "1.0.0",
|
|
330
|
+
createdAt: new Date().toISOString(),
|
|
331
|
+
updatedAt: new Date().toISOString(),
|
|
332
|
+
author: cloned.metadata?.author,
|
|
333
|
+
tags: cloned.metadata?.tags
|
|
334
|
+
};
|
|
335
|
+
return cloned;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for FlowDrop Workflow Library
|
|
3
|
+
*/
|
|
4
|
+
import type { NodeMetadata, Workflow, ExecutionResult } from "../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* HTTP API client for FlowDrop
|
|
7
|
+
*/
|
|
8
|
+
export declare class FlowDropApiClient {
|
|
9
|
+
private baseUrl;
|
|
10
|
+
private headers;
|
|
11
|
+
constructor(baseUrl: string, apiKey?: string);
|
|
12
|
+
/**
|
|
13
|
+
* Make HTTP request with error handling
|
|
14
|
+
*/
|
|
15
|
+
private request;
|
|
16
|
+
/**
|
|
17
|
+
* Fetch available node types and their metadata
|
|
18
|
+
*/
|
|
19
|
+
getAvailableNodes(): Promise<NodeMetadata[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Fetch nodes by category
|
|
22
|
+
*/
|
|
23
|
+
getNodesByCategory(category: string): Promise<NodeMetadata[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Fetch a specific node's metadata
|
|
26
|
+
*/
|
|
27
|
+
getNodeMetadata(nodeId: string): Promise<NodeMetadata>;
|
|
28
|
+
/**
|
|
29
|
+
* Save a workflow
|
|
30
|
+
*/
|
|
31
|
+
saveWorkflow(workflow: Workflow): Promise<Workflow>;
|
|
32
|
+
/**
|
|
33
|
+
* Update an existing workflow
|
|
34
|
+
*/
|
|
35
|
+
updateWorkflow(workflowId: string, workflow: Partial<Workflow>): Promise<Workflow>;
|
|
36
|
+
/**
|
|
37
|
+
* Load a workflow by ID
|
|
38
|
+
*/
|
|
39
|
+
loadWorkflow(workflowId: string): Promise<Workflow>;
|
|
40
|
+
/**
|
|
41
|
+
* List all workflows
|
|
42
|
+
*/
|
|
43
|
+
listWorkflows(): Promise<Workflow[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Delete a workflow
|
|
46
|
+
*/
|
|
47
|
+
deleteWorkflow(workflowId: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Execute a workflow
|
|
50
|
+
*/
|
|
51
|
+
executeWorkflow(workflowId: string, inputs?: Record<string, unknown>): Promise<ExecutionResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Get execution status
|
|
54
|
+
*/
|
|
55
|
+
getExecutionStatus(executionId: string): Promise<ExecutionResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Cancel workflow execution
|
|
58
|
+
*/
|
|
59
|
+
cancelExecution(executionId: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Get execution logs
|
|
62
|
+
*/
|
|
63
|
+
getExecutionLogs(executionId: string): Promise<string[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Validate workflow configuration
|
|
66
|
+
*/
|
|
67
|
+
validateWorkflow(workflow: Workflow): Promise<{
|
|
68
|
+
valid: boolean;
|
|
69
|
+
errors: string[];
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Export workflow as JSON
|
|
73
|
+
*/
|
|
74
|
+
exportWorkflow(workflowId: string): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Import workflow from JSON
|
|
77
|
+
*/
|
|
78
|
+
importWorkflow(workflowJson: string): Promise<Workflow>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for FlowDrop Workflow Library
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* HTTP API client for FlowDrop
|
|
6
|
+
*/
|
|
7
|
+
export class FlowDropApiClient {
|
|
8
|
+
baseUrl;
|
|
9
|
+
headers;
|
|
10
|
+
constructor(baseUrl, apiKey) {
|
|
11
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
12
|
+
this.headers = {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
};
|
|
15
|
+
if (apiKey) {
|
|
16
|
+
this.headers["Authorization"] = `Bearer ${apiKey}`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Make HTTP request with error handling
|
|
21
|
+
*/
|
|
22
|
+
async request(endpoint, options = {}) {
|
|
23
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
24
|
+
const config = {
|
|
25
|
+
headers: this.headers,
|
|
26
|
+
...options,
|
|
27
|
+
};
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(url, config);
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
32
|
+
}
|
|
33
|
+
const data = await response.json();
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error("API request failed:", error);
|
|
38
|
+
throw new Error(`API request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Fetch available node types and their metadata
|
|
43
|
+
*/
|
|
44
|
+
async getAvailableNodes() {
|
|
45
|
+
const response = await this.request("/api/nodes");
|
|
46
|
+
if (!response.success || !response.data) {
|
|
47
|
+
throw new Error(response.error || "Failed to fetch available nodes");
|
|
48
|
+
}
|
|
49
|
+
return response.data;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Fetch nodes by category
|
|
53
|
+
*/
|
|
54
|
+
async getNodesByCategory(category) {
|
|
55
|
+
const response = await this.request(`/api/nodes?category=${encodeURIComponent(category)}`);
|
|
56
|
+
if (!response.success || !response.data) {
|
|
57
|
+
throw new Error(response.error || "Failed to fetch nodes by category");
|
|
58
|
+
}
|
|
59
|
+
return response.data;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Fetch a specific node's metadata
|
|
63
|
+
*/
|
|
64
|
+
async getNodeMetadata(nodeId) {
|
|
65
|
+
const response = await this.request(`/api/nodes/${encodeURIComponent(nodeId)}`);
|
|
66
|
+
if (!response.success || !response.data) {
|
|
67
|
+
throw new Error(response.error || "Failed to fetch node metadata");
|
|
68
|
+
}
|
|
69
|
+
return response.data;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Save a workflow
|
|
73
|
+
*/
|
|
74
|
+
async saveWorkflow(workflow) {
|
|
75
|
+
const response = await this.request("/api/workflows", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: JSON.stringify(workflow),
|
|
78
|
+
});
|
|
79
|
+
if (!response.success || !response.data) {
|
|
80
|
+
throw new Error(response.error || "Failed to save workflow");
|
|
81
|
+
}
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Update an existing workflow
|
|
86
|
+
*/
|
|
87
|
+
async updateWorkflow(workflowId, workflow) {
|
|
88
|
+
const response = await this.request(`/api/workflows/${encodeURIComponent(workflowId)}`, {
|
|
89
|
+
method: "PUT",
|
|
90
|
+
body: JSON.stringify(workflow),
|
|
91
|
+
});
|
|
92
|
+
if (!response.success || !response.data) {
|
|
93
|
+
throw new Error(response.error || "Failed to update workflow");
|
|
94
|
+
}
|
|
95
|
+
return response.data;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Load a workflow by ID
|
|
99
|
+
*/
|
|
100
|
+
async loadWorkflow(workflowId) {
|
|
101
|
+
const response = await this.request(`/api/workflows/${encodeURIComponent(workflowId)}`);
|
|
102
|
+
if (!response.success || !response.data) {
|
|
103
|
+
throw new Error(response.error || "Failed to load workflow");
|
|
104
|
+
}
|
|
105
|
+
return response.data;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* List all workflows
|
|
109
|
+
*/
|
|
110
|
+
async listWorkflows() {
|
|
111
|
+
const response = await this.request("/api/workflows");
|
|
112
|
+
if (!response.success || !response.data) {
|
|
113
|
+
throw new Error(response.error || "Failed to list workflows");
|
|
114
|
+
}
|
|
115
|
+
return response.data;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Delete a workflow
|
|
119
|
+
*/
|
|
120
|
+
async deleteWorkflow(workflowId) {
|
|
121
|
+
const response = await this.request(`/api/workflows/${encodeURIComponent(workflowId)}`, {
|
|
122
|
+
method: "DELETE",
|
|
123
|
+
});
|
|
124
|
+
if (!response.success) {
|
|
125
|
+
throw new Error(response.error || "Failed to delete workflow");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Execute a workflow
|
|
130
|
+
*/
|
|
131
|
+
async executeWorkflow(workflowId, inputs) {
|
|
132
|
+
const response = await this.request(`/api/workflows/${encodeURIComponent(workflowId)}/execute`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
body: JSON.stringify({ inputs }),
|
|
135
|
+
});
|
|
136
|
+
if (!response.success || !response.data) {
|
|
137
|
+
throw new Error(response.error || "Failed to execute workflow");
|
|
138
|
+
}
|
|
139
|
+
return response.data;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get execution status
|
|
143
|
+
*/
|
|
144
|
+
async getExecutionStatus(executionId) {
|
|
145
|
+
const response = await this.request(`/api/executions/${encodeURIComponent(executionId)}`);
|
|
146
|
+
if (!response.success || !response.data) {
|
|
147
|
+
throw new Error(response.error || "Failed to get execution status");
|
|
148
|
+
}
|
|
149
|
+
return response.data;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Cancel workflow execution
|
|
153
|
+
*/
|
|
154
|
+
async cancelExecution(executionId) {
|
|
155
|
+
const response = await this.request(`/api/executions/${encodeURIComponent(executionId)}/cancel`, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
});
|
|
158
|
+
if (!response.success) {
|
|
159
|
+
throw new Error(response.error || "Failed to cancel execution");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get execution logs
|
|
164
|
+
*/
|
|
165
|
+
async getExecutionLogs(executionId) {
|
|
166
|
+
const response = await this.request(`/api/executions/${encodeURIComponent(executionId)}/logs`);
|
|
167
|
+
if (!response.success || !response.data) {
|
|
168
|
+
throw new Error(response.error || "Failed to get execution logs");
|
|
169
|
+
}
|
|
170
|
+
return response.data;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Validate workflow configuration
|
|
174
|
+
*/
|
|
175
|
+
async validateWorkflow(workflow) {
|
|
176
|
+
const response = await this.request("/api/workflows/validate", {
|
|
177
|
+
method: "POST",
|
|
178
|
+
body: JSON.stringify(workflow),
|
|
179
|
+
});
|
|
180
|
+
if (!response.success || !response.data) {
|
|
181
|
+
throw new Error(response.error || "Failed to validate workflow");
|
|
182
|
+
}
|
|
183
|
+
return response.data;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Export workflow as JSON
|
|
187
|
+
*/
|
|
188
|
+
async exportWorkflow(workflowId) {
|
|
189
|
+
const response = await this.request(`/api/workflows/${encodeURIComponent(workflowId)}/export`);
|
|
190
|
+
if (!response.success || !response.data) {
|
|
191
|
+
throw new Error(response.error || "Failed to export workflow");
|
|
192
|
+
}
|
|
193
|
+
return response.data;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Import workflow from JSON
|
|
197
|
+
*/
|
|
198
|
+
async importWorkflow(workflowJson) {
|
|
199
|
+
const response = await this.request("/api/workflows/import", {
|
|
200
|
+
method: "POST",
|
|
201
|
+
body: JSON.stringify({ workflow: workflowJson }),
|
|
202
|
+
});
|
|
203
|
+
if (!response.success || !response.data) {
|
|
204
|
+
throw new Error(response.error || "Failed to import workflow");
|
|
205
|
+
}
|
|
206
|
+
return response.data;
|
|
207
|
+
}
|
|
208
|
+
}
|
package/dist/app.css
ADDED
|
File without changes
|