1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct NodeTemplate {
12 pub id: String,
13 #[serde(rename = "type")]
14 pub type_name: String,
15 pub title: String,
16 pub subtitle: Option<String>,
17 pub category: String,
18 pub subcategory: Option<String>,
19 pub description: String,
20 pub icon: String,
21 pub variant: Option<String>,
22 pub shape: Option<NodeShape>,
23 pub size: Option<NodeSize>,
24 pub ports: Vec<Port>,
25 pub properties: Option<HashMap<String, PropertyDefinition>>,
26 #[serde(rename = "propertyRules")]
27 pub property_rules: Option<PropertyRules>,
28 pub runtime: Option<RuntimeRequirements>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum NodeShape {
35 Rectangle,
36 Circle,
37 Diamond,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(rename_all = "lowercase")]
43pub enum NodeSize {
44 Small,
45 Medium,
46 Large,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct Port {
52 pub id: String,
53 pub label: String,
54 #[serde(rename = "type")]
55 pub port_type: PortType,
56 pub position: PortPosition,
57 #[serde(rename = "dataType")]
58 pub data_type: Option<String>,
59 pub required: Option<bool>,
60 pub multiple: Option<bool>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "lowercase")]
66pub enum PortType {
67 Input,
68 Output,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "lowercase")]
74pub enum PortPosition {
75 Left,
76 Right,
77 Top,
78 Bottom,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct PropertyDefinition {
84 #[serde(rename = "type")]
85 pub property_type: PropertyType,
86 pub label: Option<String>,
87 pub description: Option<String>,
88 #[serde(rename = "defaultValue")]
89 pub default_value: Option<serde_json::Value>,
90 pub options: Option<Vec<serde_json::Value>>,
91 pub validation: Option<PropertyValidation>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96#[serde(rename_all = "kebab-case")]
97pub enum PropertyType {
98 String,
99 Number,
100 Boolean,
101 Select,
102 CodeEditor,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct PropertyValidation {
108 pub required: Option<bool>,
109 pub min: Option<f64>,
110 pub max: Option<f64>,
111 pub pattern: Option<String>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct PropertyRules {
117 pub triggers: Vec<String>,
118 pub rules: Vec<PropertyRule>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct PropertyRule {
124 pub when: String,
125 pub updates: HashMap<String, serde_json::Value>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct RuntimeRequirements {
131 pub executor: String,
132 pub version: Option<String>,
133 #[serde(rename = "requiredEnvVars")]
134 pub required_env_vars: Option<Vec<String>>,
135 pub capabilities: Option<Vec<String>>,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct RegisterTemplatesRequest {
141 pub namespace: String,
142 pub templates: Vec<NodeTemplate>,
143 #[serde(rename = "webhookUrl")]
144 pub webhook_url: Option<String>,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct RegisterTemplatesResponse {
150 pub registered: usize,
151 pub templates: Vec<TemplateRegistrationResult>,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct TemplateRegistrationResult {
157 pub id: String,
158 #[serde(rename = "globalId")]
159 pub global_id: String,
160 pub status: TemplateRegistrationStatus,
161 pub error: Option<String>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166#[serde(rename_all = "lowercase")]
167pub enum TemplateRegistrationStatus {
168 Registered,
169 Updated,
170 Error,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct CreateWorkflowRequest {
176 pub name: String,
177 pub description: Option<String>,
178 pub metadata: Option<HashMap<String, serde_json::Value>>,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct CreateWorkflowResponse {
184 #[serde(rename = "workflowId")]
185 pub workflow_id: String,
186 #[serde(rename = "graphId")]
187 pub graph_id: String,
188 #[serde(rename = "embedUrl")]
189 pub embed_url: String,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct Position {
195 pub x: f64,
196 pub y: f64,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct AddNodeRequest {
202 #[serde(rename = "workflowId")]
203 pub workflow_id: String,
204 #[serde(rename = "graphId")]
205 pub graph_id: Option<String>,
206 #[serde(rename = "templateId")]
207 pub template_id: String,
208 pub position: Position,
209 #[serde(rename = "propertyValues")]
210 pub property_values: Option<HashMap<String, serde_json::Value>>,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct AddNodeResponse {
216 #[serde(rename = "nodeId")]
217 pub node_id: String,
218 pub node: NodeInfo,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct NodeInfo {
224 pub id: String,
225 #[serde(rename = "type")]
226 pub node_type: String,
227 pub position: Position,
228 pub metadata: serde_json::Value,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct NodePort {
234 #[serde(rename = "nodeId")]
235 pub node_id: String,
236 #[serde(rename = "portId")]
237 pub port_id: String,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct ConnectNodesRequest {
243 #[serde(rename = "workflowId")]
244 pub workflow_id: String,
245 #[serde(rename = "graphId")]
246 pub graph_id: Option<String>,
247 pub source: NodePort,
248 pub target: NodePort,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct CreateGroupRequest {
254 #[serde(rename = "workflowId")]
255 pub workflow_id: String,
256 #[serde(rename = "graphId")]
257 pub graph_id: Option<String>,
258 pub title: String,
259 #[serde(rename = "nodeIds")]
260 pub node_ids: Vec<String>,
261 pub color: Option<String>,
262 pub description: Option<String>,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct CreateGroupResponse {
268 pub success: bool,
269 #[serde(rename = "groupId")]
270 pub group_id: String,
271 pub group: serde_json::Value,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct RemoveConnectionRequest {
277 #[serde(rename = "workflowId")]
278 pub workflow_id: String,
279 #[serde(rename = "graphId")]
280 pub graph_id: Option<String>,
281 #[serde(rename = "connectionId")]
282 pub connection_id: String,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct RemoveConnectionResponse {
288 pub success: bool,
289 pub message: String,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct UpdateGroupRequest {
295 #[serde(rename = "workflowId")]
296 pub workflow_id: String,
297 #[serde(rename = "graphId")]
298 pub graph_id: Option<String>,
299 #[serde(rename = "groupId")]
300 pub group_id: String,
301 pub title: Option<String>,
302 #[serde(rename = "nodeIds")]
303 pub node_ids: Option<Vec<String>>,
304 pub color: Option<String>,
305 pub description: Option<String>,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct UpdateGroupResponse {
311 pub success: bool,
312 pub group: serde_json::Value,
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct RemoveGroupRequest {
318 #[serde(rename = "workflowId")]
319 pub workflow_id: String,
320 #[serde(rename = "graphId")]
321 pub graph_id: Option<String>,
322 #[serde(rename = "groupId")]
323 pub group_id: String,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct RemoveGroupResponse {
329 pub success: bool,
330 pub message: String,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct CreateTraceSessionRequest {
336 #[serde(rename = "workflowId")]
337 pub workflow_id: String,
338 #[serde(rename = "workflowVersionId")]
339 pub workflow_version_id: Option<String>,
340 #[serde(rename = "executionId")]
341 pub execution_id: String,
342 pub metadata: Option<TraceMetadata>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct TraceMetadata {
348 pub trigger: Option<String>,
349 pub environment: Option<String>,
350 pub tags: Vec<String>,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct CreateTraceSessionResponse {
356 #[serde(rename = "sessionId")]
357 pub session_id: String,
358 #[serde(rename = "workflowId")]
359 pub workflow_id: String,
360 #[serde(rename = "executionId")]
361 pub execution_id: String,
362 #[serde(rename = "createdAt")]
363 pub created_at: DateTime<Utc>,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct TraceEvent {
369 pub timestamp: i64,
370 #[serde(rename = "nodeId")]
371 pub node_id: String,
372 #[serde(rename = "portId")]
373 pub port_id: Option<String>,
374 #[serde(rename = "eventType")]
375 pub event_type: TraceEventType,
376 pub data: TraceData,
377 pub duration: Option<std::time::Duration>,
378 pub metadata: Option<TraceEventMetadata>,
379 pub error: Option<TraceError>,
380}
381
382impl Default for TraceEvent {
383 fn default() -> Self {
384 Self {
385 timestamp: chrono::Utc::now().timestamp_millis(),
386 node_id: String::new(),
387 port_id: None,
388 event_type: TraceEventType::Output,
389 data: TraceData::default(),
390 duration: None,
391 metadata: None,
392 error: None,
393 }
394 }
395}
396
397#[derive(Debug, Clone, Serialize, Deserialize)]
399#[serde(rename_all = "lowercase")]
400pub enum TraceEventType {
401 Input,
402 Output,
403 Error,
404 Log,
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize)]
409pub struct TraceData {
410 pub size: usize,
411 #[serde(rename = "type")]
412 pub data_type: String,
413 pub preview: Option<serde_json::Value>,
414 #[serde(rename = "fullData")]
415 pub full_data: Option<serde_json::Value>,
416}
417
418impl Default for TraceData {
419 fn default() -> Self {
420 Self {
421 size: 0,
422 data_type: "application/json".to_string(),
423 preview: None,
424 full_data: None,
425 }
426 }
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct TraceEventMetadata {
432 #[serde(rename = "cpuUsage")]
433 pub cpu_usage: Option<f64>,
434 #[serde(rename = "memoryUsage")]
435 pub memory_usage: Option<u64>,
436 pub custom: Option<HashMap<String, serde_json::Value>>,
437}
438
439#[derive(Debug, Clone, Serialize, Deserialize)]
441pub struct TraceError {
442 pub message: String,
443 pub stack: Option<String>,
444 pub code: Option<String>,
445}
446
447#[derive(Debug, Clone, Serialize, Deserialize)]
449#[serde(rename_all = "lowercase")]
450pub enum TraceStatus {
451 Running,
452 Completed,
453 Failed,
454 Cancelled,
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct SubmitTraceEventsRequest {
460 pub events: Vec<TraceEvent>,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct WebhookConfig {
466 pub namespace: String,
467 pub url: String,
468 pub events: Option<Vec<String>>,
469 pub headers: Option<HashMap<String, String>>,
470 pub metadata: Option<HashMap<String, serde_json::Value>>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct WebhookRegistrationResponse {
476 #[serde(rename = "webhookId")]
477 pub webhook_id: String,
478 pub namespace: String,
479 pub url: String,
480 pub events: Vec<String>,
481 #[serde(rename = "isActive")]
482 pub is_active: bool,
483 #[serde(rename = "createdAt")]
484 pub created_at: DateTime<Utc>,
485}
486
487#[derive(Debug, Clone, Serialize, Deserialize)]
489pub struct HealthCheckResponse {
490 pub status: HealthStatus,
491 pub version: String,
492 pub services: HashMap<String, HealthStatus>,
493}
494
495#[derive(Debug, Clone, Serialize, Deserialize)]
497#[serde(rename_all = "lowercase")]
498pub enum HealthStatus {
499 Healthy,
500 Unhealthy,
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct TestWebhookResponse {
506 pub success: bool,
507 #[serde(rename = "statusCode")]
508 pub status_code: u16,
509 #[serde(rename = "responseTimeMs")]
510 pub response_time_ms: u64,
511 pub error: Option<String>,
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517
518 #[test]
519 fn test_node_template_serialization() {
520 let template = NodeTemplate {
521 id: "test-id".to_string(),
522 type_name: "processor".to_string(),
523 title: "Test Node".to_string(),
524 subtitle: None,
525 category: "Processing".to_string(),
526 subcategory: None,
527 description: "Test description".to_string(),
528 icon: "processor".to_string(),
529 variant: None,
530 shape: Some(NodeShape::Rectangle),
531 size: Some(NodeSize::Medium),
532 ports: vec![],
533 properties: None,
534 property_rules: None,
535 runtime: None,
536 };
537
538 let json = serde_json::to_string(&template).unwrap();
539 assert!(json.contains("test-id"));
540
541 let deserialized: NodeTemplate = serde_json::from_str(&json).unwrap();
542 assert_eq!(deserialized.id, template.id);
543 }
544
545 #[test]
546 fn test_trace_event_default() {
547 let event = TraceEvent::default();
548 assert!(!event.node_id.is_empty() || event.node_id.is_empty()); assert!(matches!(event.event_type, TraceEventType::Output));
550 }
551
552 #[test]
553 fn test_position_serialization() {
554 let position = Position { x: 100.0, y: 200.0 };
555 let json = serde_json::to_string(&position).unwrap();
556 let deserialized: Position = serde_json::from_str(&json).unwrap();
557 assert_eq!(deserialized.x, 100.0);
558 assert_eq!(deserialized.y, 200.0);
559 }
560}