Skip to main content

harn_vm/triggers/event/
payloads.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use serde_json::Value as JsonValue;
5use time::OffsetDateTime;
6
7use super::util::{parse_json_i64ish, parse_string_array};
8
9#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
10pub struct GitHubEventCommon {
11    pub event: String,
12    pub action: Option<String>,
13    pub delivery_id: Option<String>,
14    pub installation_id: Option<i64>,
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub topic: Option<String>,
17    #[serde(default, skip_serializing_if = "Option::is_none")]
18    pub repository: Option<JsonValue>,
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub repo: Option<JsonValue>,
21    pub raw: JsonValue,
22}
23
24#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
25pub struct GitHubIssuesEventPayload {
26    #[serde(flatten)]
27    pub common: GitHubEventCommon,
28    pub issue: JsonValue,
29}
30
31#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
32pub struct GitHubPullRequestEventPayload {
33    #[serde(flatten)]
34    pub common: GitHubEventCommon,
35    pub pull_request: JsonValue,
36}
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
39pub struct GitHubIssueCommentEventPayload {
40    #[serde(flatten)]
41    pub common: GitHubEventCommon,
42    pub issue: JsonValue,
43    pub comment: JsonValue,
44}
45
46#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
47pub struct GitHubPullRequestReviewEventPayload {
48    #[serde(flatten)]
49    pub common: GitHubEventCommon,
50    pub pull_request: JsonValue,
51    pub review: JsonValue,
52}
53
54#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
55pub struct GitHubPushEventPayload {
56    #[serde(flatten)]
57    pub common: GitHubEventCommon,
58    #[serde(default)]
59    pub commits: Vec<JsonValue>,
60    pub distinct_size: Option<i64>,
61}
62
63#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
64pub struct GitHubWorkflowRunEventPayload {
65    #[serde(flatten)]
66    pub common: GitHubEventCommon,
67    pub workflow_run: JsonValue,
68}
69
70#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
71pub struct GitHubDeploymentStatusEventPayload {
72    #[serde(flatten)]
73    pub common: GitHubEventCommon,
74    pub deployment_status: JsonValue,
75    pub deployment: JsonValue,
76}
77
78#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
79pub struct GitHubCheckRunEventPayload {
80    #[serde(flatten)]
81    pub common: GitHubEventCommon,
82    pub check_run: JsonValue,
83}
84
85#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
86pub struct GitHubCheckSuiteEventPayload {
87    #[serde(flatten)]
88    pub common: GitHubEventCommon,
89    pub check_suite: JsonValue,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub check_suite_id: Option<i64>,
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub pull_request_number: Option<i64>,
94    #[serde(default, skip_serializing_if = "Option::is_none")]
95    pub head_sha: Option<String>,
96    #[serde(default, skip_serializing_if = "Option::is_none")]
97    pub head_ref: Option<String>,
98    #[serde(default, skip_serializing_if = "Option::is_none")]
99    pub base_ref: Option<String>,
100    #[serde(default, skip_serializing_if = "Option::is_none")]
101    pub status: Option<String>,
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub conclusion: Option<String>,
104}
105
106#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
107pub struct GitHubStatusEventPayload {
108    #[serde(flatten)]
109    pub common: GitHubEventCommon,
110    #[serde(default, skip_serializing_if = "Option::is_none")]
111    pub commit_status: Option<JsonValue>,
112    #[serde(default, skip_serializing_if = "Option::is_none")]
113    pub status_id: Option<i64>,
114    #[serde(default, skip_serializing_if = "Option::is_none")]
115    pub head_sha: Option<String>,
116    #[serde(default, skip_serializing_if = "Option::is_none")]
117    pub head_ref: Option<String>,
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub base_ref: Option<String>,
120    #[serde(default, skip_serializing_if = "Option::is_none")]
121    pub state: Option<String>,
122    #[serde(default, skip_serializing_if = "Option::is_none")]
123    pub context: Option<String>,
124    #[serde(default, skip_serializing_if = "Option::is_none")]
125    pub target_url: Option<String>,
126}
127
128#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
129pub struct GitHubMergeGroupEventPayload {
130    #[serde(flatten)]
131    pub common: GitHubEventCommon,
132    pub merge_group: JsonValue,
133    #[serde(default, skip_serializing_if = "Option::is_none")]
134    pub merge_group_id: Option<JsonValue>,
135    #[serde(default, skip_serializing_if = "Option::is_none")]
136    pub head_sha: Option<String>,
137    #[serde(default, skip_serializing_if = "Option::is_none")]
138    pub head_ref: Option<String>,
139    #[serde(default, skip_serializing_if = "Option::is_none")]
140    pub base_sha: Option<String>,
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub base_ref: Option<String>,
143    #[serde(default)]
144    pub pull_requests: Vec<JsonValue>,
145    #[serde(default)]
146    pub pull_request_numbers: Vec<i64>,
147}
148
149#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
150pub struct GitHubInstallationEventPayload {
151    #[serde(flatten)]
152    pub common: GitHubEventCommon,
153    #[serde(default, skip_serializing_if = "Option::is_none")]
154    pub installation: Option<JsonValue>,
155    #[serde(default, skip_serializing_if = "Option::is_none")]
156    pub account: Option<JsonValue>,
157    #[serde(default, skip_serializing_if = "Option::is_none")]
158    pub installation_state: Option<String>,
159    #[serde(default, skip_serializing_if = "Option::is_none")]
160    pub suspended: Option<bool>,
161    #[serde(default, skip_serializing_if = "Option::is_none")]
162    pub revoked: Option<bool>,
163    #[serde(default)]
164    pub repositories: Vec<JsonValue>,
165}
166
167#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
168pub struct GitHubInstallationRepositoriesEventPayload {
169    #[serde(flatten)]
170    pub common: GitHubEventCommon,
171    #[serde(default, skip_serializing_if = "Option::is_none")]
172    pub installation: Option<JsonValue>,
173    #[serde(default, skip_serializing_if = "Option::is_none")]
174    pub account: Option<JsonValue>,
175    #[serde(default, skip_serializing_if = "Option::is_none")]
176    pub installation_state: Option<String>,
177    #[serde(default, skip_serializing_if = "Option::is_none")]
178    pub suspended: Option<bool>,
179    #[serde(default, skip_serializing_if = "Option::is_none")]
180    pub revoked: Option<bool>,
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub repository_selection: Option<String>,
183    #[serde(default)]
184    pub repositories_added: Vec<JsonValue>,
185    #[serde(default)]
186    pub repositories_removed: Vec<JsonValue>,
187}
188
189#[derive(Clone, Debug, PartialEq, Serialize)]
190#[serde(untagged)]
191pub enum GitHubEventPayload {
192    Issues(GitHubIssuesEventPayload),
193    PullRequest(GitHubPullRequestEventPayload),
194    IssueComment(GitHubIssueCommentEventPayload),
195    PullRequestReview(GitHubPullRequestReviewEventPayload),
196    Push(GitHubPushEventPayload),
197    WorkflowRun(GitHubWorkflowRunEventPayload),
198    DeploymentStatus(GitHubDeploymentStatusEventPayload),
199    CheckRun(GitHubCheckRunEventPayload),
200    CheckSuite(GitHubCheckSuiteEventPayload),
201    Status(GitHubStatusEventPayload),
202    MergeGroup(GitHubMergeGroupEventPayload),
203    Installation(GitHubInstallationEventPayload),
204    InstallationRepositories(GitHubInstallationRepositoriesEventPayload),
205    Other(GitHubEventCommon),
206}
207
208// Manual `Deserialize` that dispatches on the `event` field. An untagged
209// enum cannot reliably round-trip these variants because `Push` and the
210// all-optional installation/status variants will accept payloads that
211// belong to a different event kind.
212impl<'de> Deserialize<'de> for GitHubEventPayload {
213    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
214    where
215        D: Deserializer<'de>,
216    {
217        let value = JsonValue::deserialize(deserializer)?;
218        let kind = value
219            .get("event")
220            .and_then(JsonValue::as_str)
221            .unwrap_or("")
222            .to_string();
223        let from_value = |v: JsonValue| -> Result<GitHubEventPayload, D::Error> {
224            let payload = match kind.as_str() {
225                "issues" => GitHubEventPayload::Issues(
226                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
227                ),
228                "pull_request" => GitHubEventPayload::PullRequest(
229                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
230                ),
231                "issue_comment" => GitHubEventPayload::IssueComment(
232                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
233                ),
234                "pull_request_review" => GitHubEventPayload::PullRequestReview(
235                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
236                ),
237                "push" => GitHubEventPayload::Push(
238                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
239                ),
240                "workflow_run" => GitHubEventPayload::WorkflowRun(
241                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
242                ),
243                "deployment_status" => GitHubEventPayload::DeploymentStatus(
244                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
245                ),
246                "check_run" => GitHubEventPayload::CheckRun(
247                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
248                ),
249                "check_suite" => GitHubEventPayload::CheckSuite(
250                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
251                ),
252                "status" => GitHubEventPayload::Status(
253                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
254                ),
255                "merge_group" => GitHubEventPayload::MergeGroup(
256                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
257                ),
258                "installation" => GitHubEventPayload::Installation(
259                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
260                ),
261                "installation_repositories" => GitHubEventPayload::InstallationRepositories(
262                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
263                ),
264                _ => GitHubEventPayload::Other(
265                    serde_json::from_value(v).map_err(serde::de::Error::custom)?,
266                ),
267            };
268            Ok(payload)
269        };
270        from_value(value)
271    }
272}
273
274#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
275pub struct SlackEventCommon {
276    pub event: String,
277    pub event_id: Option<String>,
278    pub api_app_id: Option<String>,
279    pub team_id: Option<String>,
280    pub channel_id: Option<String>,
281    pub user_id: Option<String>,
282    pub event_ts: Option<String>,
283    pub raw: JsonValue,
284}
285
286#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
287pub struct SlackMessageEventPayload {
288    #[serde(flatten)]
289    pub common: SlackEventCommon,
290    pub subtype: Option<String>,
291    pub channel_type: Option<String>,
292    pub channel: Option<String>,
293    pub user: Option<String>,
294    pub text: Option<String>,
295    pub ts: Option<String>,
296    pub thread_ts: Option<String>,
297}
298
299#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
300pub struct SlackAppMentionEventPayload {
301    #[serde(flatten)]
302    pub common: SlackEventCommon,
303    pub channel: Option<String>,
304    pub user: Option<String>,
305    pub text: Option<String>,
306    pub ts: Option<String>,
307    pub thread_ts: Option<String>,
308}
309
310#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
311pub struct SlackReactionAddedEventPayload {
312    #[serde(flatten)]
313    pub common: SlackEventCommon,
314    pub reaction: Option<String>,
315    pub item_user: Option<String>,
316    pub item: JsonValue,
317}
318
319#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
320pub struct SlackAppHomeOpenedEventPayload {
321    #[serde(flatten)]
322    pub common: SlackEventCommon,
323    pub user: Option<String>,
324    pub channel: Option<String>,
325    pub tab: Option<String>,
326    pub view: JsonValue,
327}
328
329#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
330pub struct SlackAssistantThreadStartedEventPayload {
331    #[serde(flatten)]
332    pub common: SlackEventCommon,
333    pub assistant_thread: JsonValue,
334    pub thread_ts: Option<String>,
335    pub context: JsonValue,
336}
337
338#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
339#[serde(untagged)]
340pub enum SlackEventPayload {
341    Message(SlackMessageEventPayload),
342    AppMention(SlackAppMentionEventPayload),
343    ReactionAdded(SlackReactionAddedEventPayload),
344    AppHomeOpened(SlackAppHomeOpenedEventPayload),
345    AssistantThreadStarted(SlackAssistantThreadStartedEventPayload),
346    Other(SlackEventCommon),
347}
348
349#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
350pub struct LinearEventCommon {
351    pub event: String,
352    pub action: Option<String>,
353    pub delivery_id: Option<String>,
354    pub organization_id: Option<String>,
355    pub webhook_timestamp: Option<i64>,
356    pub webhook_id: Option<String>,
357    pub url: Option<String>,
358    pub created_at: Option<String>,
359    pub actor: JsonValue,
360    pub raw: JsonValue,
361}
362
363#[derive(Clone, Debug, PartialEq)]
364pub enum LinearIssueChange {
365    Title { previous: Option<String> },
366    Description { previous: Option<String> },
367    Priority { previous: Option<i64> },
368    Estimate { previous: Option<i64> },
369    StateId { previous: Option<String> },
370    TeamId { previous: Option<String> },
371    AssigneeId { previous: Option<String> },
372    ProjectId { previous: Option<String> },
373    CycleId { previous: Option<String> },
374    DueDate { previous: Option<String> },
375    ParentId { previous: Option<String> },
376    SortOrder { previous: Option<f64> },
377    LabelIds { previous: Vec<String> },
378    CompletedAt { previous: Option<String> },
379    Other { field: String, previous: JsonValue },
380}
381
382impl Serialize for LinearIssueChange {
383    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
384    where
385        S: Serializer,
386    {
387        let value = match self {
388            Self::Title { previous } => {
389                serde_json::json!({ "field_name": "title", "previous": previous })
390            }
391            Self::Description { previous } => {
392                serde_json::json!({ "field_name": "description", "previous": previous })
393            }
394            Self::Priority { previous } => {
395                serde_json::json!({ "field_name": "priority", "previous": previous })
396            }
397            Self::Estimate { previous } => {
398                serde_json::json!({ "field_name": "estimate", "previous": previous })
399            }
400            Self::StateId { previous } => {
401                serde_json::json!({ "field_name": "state_id", "previous": previous })
402            }
403            Self::TeamId { previous } => {
404                serde_json::json!({ "field_name": "team_id", "previous": previous })
405            }
406            Self::AssigneeId { previous } => {
407                serde_json::json!({ "field_name": "assignee_id", "previous": previous })
408            }
409            Self::ProjectId { previous } => {
410                serde_json::json!({ "field_name": "project_id", "previous": previous })
411            }
412            Self::CycleId { previous } => {
413                serde_json::json!({ "field_name": "cycle_id", "previous": previous })
414            }
415            Self::DueDate { previous } => {
416                serde_json::json!({ "field_name": "due_date", "previous": previous })
417            }
418            Self::ParentId { previous } => {
419                serde_json::json!({ "field_name": "parent_id", "previous": previous })
420            }
421            Self::SortOrder { previous } => {
422                serde_json::json!({ "field_name": "sort_order", "previous": previous })
423            }
424            Self::LabelIds { previous } => {
425                serde_json::json!({ "field_name": "label_ids", "previous": previous })
426            }
427            Self::CompletedAt { previous } => {
428                serde_json::json!({ "field_name": "completed_at", "previous": previous })
429            }
430            Self::Other { field, previous } => {
431                serde_json::json!({ "field_name": "other", "field": field, "previous": previous })
432            }
433        };
434        value.serialize(serializer)
435    }
436}
437
438impl<'de> Deserialize<'de> for LinearIssueChange {
439    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
440    where
441        D: Deserializer<'de>,
442    {
443        let value = JsonValue::deserialize(deserializer)?;
444        let field_name = value
445            .get("field_name")
446            .and_then(JsonValue::as_str)
447            .ok_or_else(|| serde::de::Error::custom("linear issue change missing field_name"))?;
448        let previous = value.get("previous").cloned().unwrap_or(JsonValue::Null);
449        Ok(match field_name {
450            "title" => Self::Title {
451                previous: previous.as_str().map(ToString::to_string),
452            },
453            "description" => Self::Description {
454                previous: previous.as_str().map(ToString::to_string),
455            },
456            "priority" => Self::Priority {
457                previous: parse_json_i64ish(&previous),
458            },
459            "estimate" => Self::Estimate {
460                previous: parse_json_i64ish(&previous),
461            },
462            "state_id" => Self::StateId {
463                previous: previous.as_str().map(ToString::to_string),
464            },
465            "team_id" => Self::TeamId {
466                previous: previous.as_str().map(ToString::to_string),
467            },
468            "assignee_id" => Self::AssigneeId {
469                previous: previous.as_str().map(ToString::to_string),
470            },
471            "project_id" => Self::ProjectId {
472                previous: previous.as_str().map(ToString::to_string),
473            },
474            "cycle_id" => Self::CycleId {
475                previous: previous.as_str().map(ToString::to_string),
476            },
477            "due_date" => Self::DueDate {
478                previous: previous.as_str().map(ToString::to_string),
479            },
480            "parent_id" => Self::ParentId {
481                previous: previous.as_str().map(ToString::to_string),
482            },
483            "sort_order" => Self::SortOrder {
484                previous: previous.as_f64(),
485            },
486            "label_ids" => Self::LabelIds {
487                previous: parse_string_array(&previous),
488            },
489            "completed_at" => Self::CompletedAt {
490                previous: previous.as_str().map(ToString::to_string),
491            },
492            "other" => Self::Other {
493                field: value
494                    .get("field")
495                    .and_then(JsonValue::as_str)
496                    .map(ToString::to_string)
497                    .unwrap_or_else(|| "unknown".to_string()),
498                previous,
499            },
500            other => Self::Other {
501                field: other.to_string(),
502                previous,
503            },
504        })
505    }
506}
507
508#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
509pub struct LinearIssueEventPayload {
510    #[serde(flatten)]
511    pub common: LinearEventCommon,
512    pub issue: JsonValue,
513    #[serde(default)]
514    pub changes: Vec<LinearIssueChange>,
515}
516
517#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
518pub struct LinearIssueCommentEventPayload {
519    #[serde(flatten)]
520    pub common: LinearEventCommon,
521    pub comment: JsonValue,
522}
523
524#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
525pub struct LinearIssueLabelEventPayload {
526    #[serde(flatten)]
527    pub common: LinearEventCommon,
528    pub label: JsonValue,
529}
530
531#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
532pub struct LinearProjectEventPayload {
533    #[serde(flatten)]
534    pub common: LinearEventCommon,
535    pub project: JsonValue,
536}
537
538#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
539pub struct LinearCycleEventPayload {
540    #[serde(flatten)]
541    pub common: LinearEventCommon,
542    pub cycle: JsonValue,
543}
544
545#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
546pub struct LinearCustomerEventPayload {
547    #[serde(flatten)]
548    pub common: LinearEventCommon,
549    pub customer: JsonValue,
550}
551
552#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
553pub struct LinearCustomerRequestEventPayload {
554    #[serde(flatten)]
555    pub common: LinearEventCommon,
556    pub customer_request: JsonValue,
557}
558
559#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
560#[serde(untagged)]
561pub enum LinearEventPayload {
562    Issue(LinearIssueEventPayload),
563    IssueComment(LinearIssueCommentEventPayload),
564    IssueLabel(LinearIssueLabelEventPayload),
565    Project(LinearProjectEventPayload),
566    Cycle(LinearCycleEventPayload),
567    Customer(LinearCustomerEventPayload),
568    CustomerRequest(LinearCustomerRequestEventPayload),
569    Other(LinearEventCommon),
570}
571
572#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
573pub struct NotionPolledChangeEvent {
574    pub resource: String,
575    pub source_id: String,
576    pub entity_id: String,
577    pub high_water_mark: String,
578    pub before: Option<JsonValue>,
579    pub after: JsonValue,
580}
581
582#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
583pub struct NotionEventPayload {
584    pub event: String,
585    pub workspace_id: Option<String>,
586    pub request_id: Option<String>,
587    pub subscription_id: Option<String>,
588    pub integration_id: Option<String>,
589    pub attempt_number: Option<u32>,
590    pub entity_id: Option<String>,
591    pub entity_type: Option<String>,
592    pub api_version: Option<String>,
593    pub verification_token: Option<String>,
594    pub polled: Option<NotionPolledChangeEvent>,
595    pub raw: JsonValue,
596}
597
598#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
599pub struct CronEventPayload {
600    pub cron_id: Option<String>,
601    pub schedule: Option<String>,
602    #[serde(with = "time::serde::rfc3339")]
603    pub tick_at: OffsetDateTime,
604    pub raw: JsonValue,
605}
606
607#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
608pub struct GenericWebhookPayload {
609    pub source: Option<String>,
610    pub content_type: Option<String>,
611    pub raw: JsonValue,
612}
613
614#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
615pub struct A2aPushPayload {
616    pub task_id: Option<String>,
617    pub task_state: Option<String>,
618    pub artifact: Option<JsonValue>,
619    pub sender: Option<String>,
620    pub raw: JsonValue,
621    pub kind: String,
622}
623
624#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
625pub struct StreamEventPayload {
626    pub event: String,
627    pub source: Option<String>,
628    pub stream: Option<String>,
629    pub partition: Option<String>,
630    pub offset: Option<String>,
631    pub key: Option<String>,
632    pub timestamp: Option<String>,
633    #[serde(default)]
634    pub headers: BTreeMap<String, String>,
635    pub raw: JsonValue,
636}
637
638#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
639pub struct ExtensionProviderPayload {
640    pub provider: String,
641    pub schema_name: String,
642    pub raw: JsonValue,
643}
644
645#[allow(clippy::large_enum_variant)]
646#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
647#[serde(untagged)]
648pub enum ProviderPayload {
649    Known(KnownProviderPayload),
650    Extension(ExtensionProviderPayload),
651}
652
653impl ProviderPayload {
654    pub fn provider(&self) -> &str {
655        match self {
656            Self::Known(known) => known.provider(),
657            Self::Extension(payload) => payload.provider.as_str(),
658        }
659    }
660}
661
662#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
663#[serde(tag = "provider")]
664pub enum KnownProviderPayload {
665    #[serde(rename = "github")]
666    GitHub(GitHubEventPayload),
667    #[serde(rename = "slack")]
668    Slack(Box<SlackEventPayload>),
669    #[serde(rename = "linear")]
670    Linear(LinearEventPayload),
671    #[serde(rename = "notion")]
672    Notion(Box<NotionEventPayload>),
673    #[serde(rename = "cron")]
674    Cron(CronEventPayload),
675    #[serde(rename = "webhook")]
676    Webhook(GenericWebhookPayload),
677    #[serde(rename = "a2a-push")]
678    A2aPush(A2aPushPayload),
679    #[serde(rename = "kafka")]
680    Kafka(StreamEventPayload),
681    #[serde(rename = "nats")]
682    Nats(StreamEventPayload),
683    #[serde(rename = "pulsar")]
684    Pulsar(StreamEventPayload),
685    #[serde(rename = "postgres-cdc")]
686    PostgresCdc(StreamEventPayload),
687    #[serde(rename = "email")]
688    Email(StreamEventPayload),
689    #[serde(rename = "websocket")]
690    Websocket(StreamEventPayload),
691}
692
693impl KnownProviderPayload {
694    pub fn provider(&self) -> &str {
695        match self {
696            Self::GitHub(_) => "github",
697            Self::Slack(_) => "slack",
698            Self::Linear(_) => "linear",
699            Self::Notion(_) => "notion",
700            Self::Cron(_) => "cron",
701            Self::Webhook(_) => "webhook",
702            Self::A2aPush(_) => "a2a-push",
703            Self::Kafka(_) => "kafka",
704            Self::Nats(_) => "nats",
705            Self::Pulsar(_) => "pulsar",
706            Self::PostgresCdc(_) => "postgres-cdc",
707            Self::Email(_) => "email",
708            Self::Websocket(_) => "websocket",
709        }
710    }
711}