Skip to main content

zeal_sdk/
types.rs

1//! Type definitions for the Zeal SDK
2//!
3//! These types mirror the TypeScript SDK types and ZIP protocol definitions
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// Node template definition
10#[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/// Node shape variants
32#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum NodeShape {
35    Rectangle,
36    Circle,
37    Diamond,
38}
39
40/// Node size variants
41#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(rename_all = "lowercase")]
43pub enum NodeSize {
44    Small,
45    Medium,
46    Large,
47}
48
49/// Port definition
50#[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/// Port type
64#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "lowercase")]
66pub enum PortType {
67    Input,
68    Output,
69}
70
71/// Port position
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "lowercase")]
74pub enum PortPosition {
75    Left,
76    Right,
77    Top,
78    Bottom,
79}
80
81/// Property definition
82#[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/// Property type
95#[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/// Property validation rules
106#[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/// Property rules for dynamic behavior
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct PropertyRules {
117    pub triggers: Vec<String>,
118    pub rules: Vec<PropertyRule>,
119}
120
121/// Individual property rule
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct PropertyRule {
124    pub when: String,
125    pub updates: HashMap<String, serde_json::Value>,
126}
127
128/// Runtime requirements
129#[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/// Register templates request
139#[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/// Register templates response
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct RegisterTemplatesResponse {
150    pub registered: usize,
151    pub templates: Vec<TemplateRegistrationResult>,
152}
153
154/// Template registration result
155#[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/// Template registration status
165#[derive(Debug, Clone, Serialize, Deserialize)]
166#[serde(rename_all = "lowercase")]
167pub enum TemplateRegistrationStatus {
168    Registered,
169    Updated,
170    Error,
171}
172
173/// Create workflow request
174#[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/// Create workflow response
182#[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/// 2D position
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct Position {
195    pub x: f64,
196    pub y: f64,
197}
198
199/// Add node request
200#[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/// Add node response
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct AddNodeResponse {
216    #[serde(rename = "nodeId")]
217    pub node_id: String,
218    pub node: NodeInfo,
219}
220
221/// Node information
222#[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/// Node port reference
232#[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/// Connect nodes request
241#[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/// Create group request
252#[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/// Create group response
266#[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/// Remove connection request
275#[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/// Remove connection response
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct RemoveConnectionResponse {
288    pub success: bool,
289    pub message: String,
290}
291
292/// Update group request
293#[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/// Update group response
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct UpdateGroupResponse {
311    pub success: bool,
312    pub group: serde_json::Value,
313}
314
315/// Remove group request
316#[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/// Remove group response
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct RemoveGroupResponse {
329    pub success: bool,
330    pub message: String,
331}
332
333/// Create trace session request
334#[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/// Trace session metadata
346#[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/// Create trace session response
354#[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/// Trace event
367#[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/// Trace event type
398#[derive(Debug, Clone, Serialize, Deserialize)]
399#[serde(rename_all = "lowercase")]
400pub enum TraceEventType {
401    Input,
402    Output,
403    Error,
404    Log,
405}
406
407/// Trace data
408#[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/// Trace event metadata
430#[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/// Trace error information
440#[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/// Trace status
448#[derive(Debug, Clone, Serialize, Deserialize)]
449#[serde(rename_all = "lowercase")]
450pub enum TraceStatus {
451    Running,
452    Completed,
453    Failed,
454    Cancelled,
455}
456
457/// Submit trace events request
458#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct SubmitTraceEventsRequest {
460    pub events: Vec<TraceEvent>,
461}
462
463/// Webhook configuration
464#[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/// Webhook registration response
474#[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/// Health check response
488#[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/// Health status
496#[derive(Debug, Clone, Serialize, Deserialize)]
497#[serde(rename_all = "lowercase")]
498pub enum HealthStatus {
499    Healthy,
500    Unhealthy,
501}
502
503/// Test webhook response
504#[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()); // Just testing compilation
549        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}