1use serde::{Deserialize, Serialize};
19use std::collections::HashMap;
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
24pub enum WebhookVersion {
25 V1,
27 V2,
29 V3,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct TriggerEvent {
36 pub id: String,
38
39 pub uuid: String,
41
42 pub user_id: String,
44
45 pub toolkit_slug: String,
47
48 pub trigger_slug: String,
50
51 pub metadata: TriggerMetadata,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub payload: Option<serde_json::Value>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub original_payload: Option<serde_json::Value>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct TriggerMetadata {
66 pub id: String,
68
69 pub uuid: String,
71
72 pub toolkit_slug: String,
74
75 pub trigger_slug: String,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub trigger_data: Option<String>,
81
82 pub trigger_config: serde_json::Value,
84
85 pub connected_account: TriggerConnectedAccount,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct TriggerConnectedAccount {
92 pub id: String,
94
95 pub uuid: String,
97
98 pub auth_config_id: String,
100
101 pub auth_config_uuid: String,
103
104 pub user_id: String,
106
107 pub status: String,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct VerifyWebhookResult {
114 pub version: WebhookVersion,
116
117 pub payload: TriggerEvent,
119
120 pub raw_payload: serde_json::Value,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct TriggerType {
127 pub slug: String,
129
130 pub name: String,
132
133 pub description: String,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub instructions: Option<String>,
139
140 #[serde(rename = "type")]
142 pub trigger_type: String,
143
144 pub toolkit: TriggerToolkitRef,
146
147 pub config: serde_json::Value,
149
150 pub payload: serde_json::Value,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub version: Option<String>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct TriggerToolkitRef {
161 pub slug: String,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub name: Option<String>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub logo: Option<String>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct TriggerInstance {
176 pub id: String,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub uuid: Option<String>,
182
183 pub trigger_name: String,
185
186 pub connected_account_id: String,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub user_id: Option<String>,
192
193 pub trigger_config: serde_json::Value,
195
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub state: Option<String>,
199
200 #[serde(skip_serializing_if = "Option::is_none")]
202 pub created_at: Option<String>,
203
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub updated_at: Option<String>,
207
208 #[serde(skip_serializing_if = "Option::is_none")]
210 pub disabled_at: Option<String>,
211}
212
213#[derive(Debug, Clone, Default, Serialize, Deserialize)]
215pub struct TriggerTypeRetrieveParams {
216 #[serde(skip_serializing_if = "Option::is_none")]
218 pub toolkit_versions: Option<String>,
219}
220
221pub type TriggerTypeRetrieveEnumResponse = Vec<String>;
225
226#[derive(Debug, Clone, Default, Serialize, Deserialize)]
228pub struct TriggerTypeListParams {
229 #[serde(skip_serializing_if = "Option::is_none")]
231 pub cursor: Option<String>,
232
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub limit: Option<u32>,
236
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub toolkit_slugs: Option<Vec<String>>,
240
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub toolkit_versions: Option<String>,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct TriggerTypeListResponse {
249 pub items: Vec<TriggerType>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub next_cursor: Option<String>,
255
256 #[serde(skip_serializing_if = "Option::is_none")]
258 pub total_pages: Option<u32>,
259
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub current_page: Option<u32>,
263
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub total_items: Option<u32>,
267}
268
269#[derive(Debug, Clone, Default, Serialize, Deserialize)]
271pub struct TriggerInstanceListParams {
272 #[serde(skip_serializing_if = "Option::is_none")]
274 pub trigger_ids: Option<Vec<String>>,
275
276 #[serde(skip_serializing_if = "Option::is_none")]
278 pub trigger_names: Option<Vec<String>>,
279
280 #[serde(skip_serializing_if = "Option::is_none")]
282 pub auth_config_ids: Option<Vec<String>>,
283
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub connected_account_ids: Option<Vec<String>>,
287
288 #[serde(skip_serializing_if = "Option::is_none")]
290 pub show_disabled: Option<bool>,
291
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub limit: Option<u32>,
295
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub cursor: Option<String>,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct TriggerInstanceListResponse {
304 pub items: Vec<TriggerInstance>,
306
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub next_cursor: Option<String>,
310
311 #[serde(skip_serializing_if = "Option::is_none")]
313 pub total_pages: Option<u32>,
314
315 #[serde(skip_serializing_if = "Option::is_none")]
317 pub current_page: Option<u32>,
318
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub total_items: Option<u32>,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct TriggerCreateParams {
327 pub slug: String,
329
330 #[serde(skip_serializing_if = "Option::is_none")]
332 pub connected_account_id: Option<String>,
333
334 #[serde(skip_serializing_if = "Option::is_none")]
336 pub user_id: Option<String>,
337
338 #[serde(skip_serializing_if = "Option::is_none")]
340 pub trigger_config: Option<HashMap<String, serde_json::Value>>,
341
342 #[serde(skip_serializing_if = "Option::is_none")]
344 pub toolkit_versions: Option<String>,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct TriggerCreateResponse {
350 pub id: String,
352
353 pub trigger_name: String,
355
356 pub connected_account_id: String,
358
359 #[serde(skip_serializing_if = "Option::is_none")]
361 pub user_id: Option<String>,
362
363 pub trigger_config: serde_json::Value,
365
366 #[serde(skip_serializing_if = "Option::is_none")]
368 pub state: Option<String>,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct WebhookVerifyParams {
374 pub id: String,
376
377 pub payload: String,
379
380 pub secret: String,
382
383 pub signature: String,
385
386 pub timestamp: String,
388
389 #[serde(skip_serializing_if = "Option::is_none")]
391 pub tolerance: Option<u32>,
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_webhook_version_serialization() {
400 let v1 = WebhookVersion::V1;
401 let json = serde_json::to_string(&v1).unwrap();
402 assert_eq!(json, "\"V1\"");
403
404 let v3 = WebhookVersion::V3;
405 let json = serde_json::to_string(&v3).unwrap();
406 assert_eq!(json, "\"V3\"");
407 }
408
409 #[test]
410 fn test_trigger_type_retrieve_params_serialization() {
411 let params = TriggerTypeRetrieveParams {
412 toolkit_versions: Some("latest".to_string()),
413 };
414
415 let value = serde_json::to_value(¶ms).unwrap();
416 assert_eq!(value["toolkit_versions"], "latest");
417 }
418
419 #[test]
420 fn test_trigger_type_retrieve_enum_response_deserialization() {
421 let payload = serde_json::json!(["GITHUB_COMMIT_EVENT", "SLACK_NEW_MESSAGE"]);
422
423 let response: TriggerTypeRetrieveEnumResponse = serde_json::from_value(payload).unwrap();
424 assert_eq!(response.len(), 2);
425 assert_eq!(response[0], "GITHUB_COMMIT_EVENT");
426 }
427
428 #[test]
429 fn test_trigger_type_list_params_default() {
430 let params = TriggerTypeListParams::default();
431 assert!(params.cursor.is_none());
432 assert!(params.limit.is_none());
433 assert!(params.toolkit_slugs.is_none());
434 }
435
436 #[test]
437 fn test_trigger_instance_list_params_default() {
438 let params = TriggerInstanceListParams::default();
439 assert!(params.trigger_ids.is_none());
440 assert!(params.trigger_names.is_none());
441 assert!(params.show_disabled.is_none());
442 }
443
444 #[test]
445 fn test_trigger_event_deserialization() {
446 let json = r#"{
447 "id": "ti_123",
448 "uuid": "uuid_123",
449 "user_id": "user_456",
450 "toolkit_slug": "github",
451 "trigger_slug": "GITHUB_COMMIT_EVENT",
452 "metadata": {
453 "id": "ti_123",
454 "uuid": "uuid_123",
455 "toolkit_slug": "github",
456 "trigger_slug": "GITHUB_COMMIT_EVENT",
457 "trigger_data": null,
458 "trigger_config": {},
459 "connected_account": {
460 "id": "ca_789",
461 "uuid": "ca_uuid_789",
462 "auth_config_id": "ac_101",
463 "auth_config_uuid": "ac_uuid_101",
464 "user_id": "user_456",
465 "status": "ACTIVE"
466 }
467 },
468 "payload": {"test": "data"},
469 "original_payload": null
470 }"#;
471
472 let event: TriggerEvent = serde_json::from_str(json).unwrap();
473 assert_eq!(event.id, "ti_123");
474 assert_eq!(event.user_id, "user_456");
475 assert_eq!(event.trigger_slug, "GITHUB_COMMIT_EVENT");
476 assert_eq!(event.metadata.connected_account.id, "ca_789");
477 }
478
479 #[test]
480 fn test_trigger_create_params() {
481 let params = TriggerCreateParams {
482 slug: "GITHUB_COMMIT_EVENT".to_string(),
483 connected_account_id: Some("ca_123".to_string()),
484 user_id: None,
485 trigger_config: Some(HashMap::from([
486 ("repo".to_string(), serde_json::json!("composio")),
487 ("owner".to_string(), serde_json::json!("composio")),
488 ])),
489 toolkit_versions: None,
490 };
491
492 assert_eq!(params.slug, "GITHUB_COMMIT_EVENT");
493 assert!(params.connected_account_id.is_some());
494 assert!(params.trigger_config.is_some());
495 }
496}