1#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
2pub struct RemoteTriggerOccurrenceRequest {
3 pub protocol_version: u32,
4 pub source_type: String,
5 pub source_key: String,
6 #[serde(default)]
7 pub payload: serde_json::Value,
8 pub idempotency_key: String,
9 #[serde(default, skip_serializing_if = "Option::is_none")]
10 pub source: Option<serde_json::Value>,
11}
12
13impl RemoteTriggerOccurrenceRequest {
14 pub fn new(
15 source_type: impl Into<String>,
16 source_key: impl Into<String>,
17 payload: serde_json::Value,
18 idempotency_key: impl Into<String>,
19 ) -> Self {
20 Self {
21 protocol_version: REMOTE_PROTOCOL_VERSION,
22 source_type: source_type.into(),
23 source_key: source_key.into(),
24 payload,
25 idempotency_key: idempotency_key.into(),
26 source: None,
27 }
28 }
29
30 pub fn with_source(mut self, source: serde_json::Value) -> Self {
31 self.source = Some(source);
32 self
33 }
34
35 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
36 ensure_protocol_version(self.protocol_version)?;
37 require_non_empty(
38 "RemoteTriggerOccurrenceRequest",
39 "source_type",
40 &self.source_type,
41 )?;
42 require_non_empty(
43 "RemoteTriggerOccurrenceRequest",
44 "source_key",
45 &self.source_key,
46 )?;
47 require_non_empty(
48 "RemoteTriggerOccurrenceRequest",
49 "idempotency_key",
50 &self.idempotency_key,
51 )
52 }
53}
54
55#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
56pub struct RemoteTriggerOccurrenceRecord {
57 pub occurrence_id: String,
58 pub source_type: String,
59 pub source_key: String,
60 #[serde(default)]
61 pub payload: serde_json::Value,
62 pub idempotency_key: String,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub source: Option<serde_json::Value>,
65 pub occurred_at_ms: u64,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
69pub struct RemoteTriggerEmitReport {
70 pub protocol_version: u32,
71 #[serde(default, skip_serializing_if = "String::is_empty")]
72 pub occurrence_id: String,
73 #[serde(default, skip_serializing_if = "Vec::is_empty")]
74 pub started_process_ids: Vec<String>,
75}
76
77impl RemoteTriggerEmitReport {
78 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
79 ensure_protocol_version(self.protocol_version)
80 }
81}
82
83#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
84pub struct RemoteTriggerSubscriptionFilter {
85 pub protocol_version: u32,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub session_id: Option<String>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub handle: Option<String>,
90 #[serde(default, skip_serializing_if = "Option::is_none")]
91 pub name: Option<String>,
92 #[serde(default, skip_serializing_if = "Option::is_none")]
93 pub source_type: Option<String>,
94 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub source_key: Option<String>,
96 #[serde(default, skip_serializing_if = "Option::is_none")]
97 pub target: Option<RemoteProcessDefinitionIdentity>,
98 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub enabled: Option<bool>,
100}
101
102impl Default for RemoteTriggerSubscriptionFilter {
103 fn default() -> Self {
104 Self {
105 protocol_version: REMOTE_PROTOCOL_VERSION,
106 session_id: None,
107 handle: None,
108 name: None,
109 source_type: None,
110 source_key: None,
111 target: None,
112 enabled: None,
113 }
114 }
115}
116
117impl RemoteTriggerSubscriptionFilter {
118 pub fn for_session(session_id: impl Into<String>) -> Self {
119 Self {
120 protocol_version: REMOTE_PROTOCOL_VERSION,
121 session_id: Some(session_id.into()),
122 ..Self::default()
123 }
124 }
125
126 pub fn for_source_type(source_type: impl Into<String>) -> Self {
127 Self {
128 protocol_version: REMOTE_PROTOCOL_VERSION,
129 source_type: Some(source_type.into()),
130 ..Self::default()
131 }
132 }
133
134 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
135 ensure_protocol_version(self.protocol_version)
136 }
137}
138
139#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
140pub struct RemoteTriggerRegistration {
141 pub handle: String,
142 pub source_key: String,
143 #[serde(default, skip_serializing_if = "Option::is_none")]
144 pub name: Option<String>,
145 pub source_type: String,
146 #[serde(default)]
147 pub source: serde_json::Value,
148 pub target: RemoteTriggerTargetSummary,
149 #[serde(default = "default_true")]
150 pub enabled: bool,
151}
152
153#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
154pub struct RemoteTriggerTargetSummary {
155 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub label: Option<String>,
157 pub identity: RemoteProcessIdentity,
158 pub input: RemoteProcessInput,
159 #[serde(default)]
160 pub inputs: RemoteTriggerInputTemplate,
161}
162
163fn default_true() -> bool {
164 true
165}
166
167#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
168#[serde(transparent)]
169pub struct RemoteTriggerInputTemplate {
170 pub entries: BTreeMap<String, RemoteTriggerInputBinding>,
171}
172
173impl RemoteTriggerInputTemplate {
174 pub fn new(entries: BTreeMap<String, RemoteTriggerInputBinding>) -> Self {
175 Self { entries }
176 }
177
178 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
179 for name in self.entries.keys() {
180 require_non_empty(type_name, "input_template key", name)?;
181 }
182 Ok(())
183 }
184}
185
186#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
187#[serde(tag = "kind", rename_all = "snake_case")]
188pub enum RemoteTriggerInputBinding {
189 Event,
190 Fixed { value: serde_json::Value },
191}
192
193#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
194pub struct RemoteTriggerSubscriptionDraft {
195 pub protocol_version: u32,
196 pub registrant: RemoteProcessOriginator,
197 pub env_ref: RemoteProcessExecutionEnvRef,
198 #[serde(default, skip_serializing_if = "Option::is_none")]
199 pub wake_target: Option<RemoteSessionScope>,
200 #[serde(default, skip_serializing_if = "Option::is_none")]
201 pub name: Option<String>,
202 pub source_type: String,
203 pub source_key: String,
204 #[serde(default)]
205 pub source: serde_json::Value,
206 #[serde(default)]
207 pub payload_schema: serde_json::Value,
208 pub target: RemoteProcessInput,
209 pub target_identity: RemoteProcessIdentity,
210 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub event_types: Vec<RemoteProcessEventType>,
212 #[serde(default)]
213 pub input_template: RemoteTriggerInputTemplate,
214 #[serde(default, skip_serializing_if = "Option::is_none")]
215 pub target_label: Option<String>,
216}
217
218impl RemoteTriggerSubscriptionDraft {
219 pub fn for_process(
220 registrant: RemoteProcessOriginator,
221 env_ref: RemoteProcessExecutionEnvRef,
222 source_type: impl Into<String>,
223 source_key: impl Into<String>,
224 target: RemoteProcessInput,
225 target_identity: RemoteProcessIdentity,
226 ) -> Self {
227 let target_label = target_identity.label.clone();
228 Self {
229 protocol_version: REMOTE_PROTOCOL_VERSION,
230 registrant,
231 env_ref,
232 wake_target: None,
233 name: None,
234 source_type: source_type.into(),
235 source_key: source_key.into(),
236 source: serde_json::Value::Object(serde_json::Map::new()),
237 payload_schema: serde_json::Value::Object(serde_json::Map::new()),
238 target,
239 target_identity,
240 event_types: Vec::new(),
241 input_template: RemoteTriggerInputTemplate::default(),
242 target_label,
243 }
244 }
245
246 pub fn with_name(mut self, name: impl Into<String>) -> Self {
247 self.name = Some(name.into());
248 self
249 }
250
251 pub fn with_source(mut self, source: serde_json::Value) -> Self {
252 self.source = source;
253 self
254 }
255
256 pub fn with_payload_schema(mut self, payload_schema: serde_json::Value) -> Self {
257 self.payload_schema = payload_schema;
258 self
259 }
260
261 pub fn with_wake_target(mut self, wake_target: RemoteSessionScope) -> Self {
262 self.wake_target = Some(wake_target);
263 self
264 }
265
266 pub fn with_event_types(
267 mut self,
268 event_types: impl IntoIterator<Item = RemoteProcessEventType>,
269 ) -> Self {
270 self.event_types = event_types.into_iter().collect();
271 self
272 }
273
274 pub fn with_input_template(mut self, input_template: RemoteTriggerInputTemplate) -> Self {
275 self.input_template = input_template;
276 self
277 }
278
279 pub fn with_target_label(mut self, target_label: impl Into<String>) -> Self {
280 self.target_label = Some(target_label.into());
281 self
282 }
283
284 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
285 ensure_protocol_version(self.protocol_version)?;
286 self.registrant.validate("RemoteTriggerSubscriptionDraft")?;
287 self.env_ref.validate("RemoteTriggerSubscriptionDraft")?;
288 if let Some(wake_target) = &self.wake_target {
289 wake_target.validate("RemoteTriggerSubscriptionDraft")?;
290 }
291 require_non_empty(
292 "RemoteTriggerSubscriptionDraft",
293 "source_type",
294 &self.source_type,
295 )?;
296 require_non_empty(
297 "RemoteTriggerSubscriptionDraft",
298 "source_key",
299 &self.source_key,
300 )?;
301 self.target.validate("RemoteTriggerSubscriptionDraft")?;
302 self.target_identity
303 .validate("RemoteTriggerSubscriptionDraft")?;
304 for event_type in &self.event_types {
305 event_type.validate("RemoteTriggerSubscriptionDraft")?;
306 }
307 validate_remote_trigger_target_label(
308 "RemoteTriggerSubscriptionDraft",
309 self.target_label.as_deref(),
310 self.target_identity.label.as_deref(),
311 )?;
312 self.input_template
313 .validate("RemoteTriggerSubscriptionDraft")
314 }
315}
316
317#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
318pub struct RemoteTriggerSubscriptionRecord {
319 pub subscription_id: String,
320 pub registrant: RemoteProcessOriginator,
321 pub env_ref: RemoteProcessExecutionEnvRef,
322 #[serde(default, skip_serializing_if = "Option::is_none")]
323 pub wake_target: Option<RemoteSessionScope>,
324 pub handle: String,
325 #[serde(default, skip_serializing_if = "Option::is_none")]
326 pub name: Option<String>,
327 pub source_type: String,
328 pub source_key: String,
329 #[serde(default)]
330 pub source: serde_json::Value,
331 #[serde(default)]
332 pub payload_schema: serde_json::Value,
333 pub target: RemoteProcessInput,
334 pub target_identity: RemoteProcessIdentity,
335 #[serde(default, skip_serializing_if = "Vec::is_empty")]
336 pub event_types: Vec<RemoteProcessEventType>,
337 #[serde(default)]
338 pub input_template: RemoteTriggerInputTemplate,
339 #[serde(default, skip_serializing_if = "Option::is_none")]
340 pub target_label: Option<String>,
341 #[serde(default = "default_true")]
342 pub enabled: bool,
343 pub created_at_ms: u64,
344 pub updated_at_ms: u64,
345}
346
347impl RemoteTriggerSubscriptionRecord {
348 pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
349 require_non_empty(type_name, "subscription_id", &self.subscription_id)?;
350 self.registrant.validate(type_name)?;
351 self.env_ref.validate(type_name)?;
352 if let Some(wake_target) = &self.wake_target {
353 wake_target.validate(type_name)?;
354 }
355 require_non_empty(type_name, "handle", &self.handle)?;
356 require_non_empty(type_name, "source_type", &self.source_type)?;
357 require_non_empty(type_name, "source_key", &self.source_key)?;
358 self.target.validate(type_name)?;
359 self.target_identity.validate(type_name)?;
360 for event_type in &self.event_types {
361 event_type.validate(type_name)?;
362 }
363 validate_remote_trigger_target_label(
364 type_name,
365 self.target_label.as_deref(),
366 self.target_identity.label.as_deref(),
367 )?;
368 self.input_template.validate(type_name)
369 }
370}
371
372fn validate_remote_trigger_target_label(
373 type_name: &'static str,
374 target_label: Option<&str>,
375 identity_label: Option<&str>,
376) -> Result<(), RemoteProtocolError> {
377 match (target_label, identity_label) {
378 (Some(target_label), Some(identity_label)) if target_label != identity_label => {
379 Err(RemoteProtocolError::InvalidEnvelope {
380 type_name,
381 message:
382 "target_label must match target_identity.label when both are present"
383 .to_string(),
384 })
385 }
386 _ => Ok(()),
387 }
388}
389
390#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
391pub struct RemoteTriggerRegisterSubscriptionRequest {
392 pub protocol_version: u32,
393 pub draft: RemoteTriggerSubscriptionDraft,
394}
395
396impl RemoteTriggerRegisterSubscriptionRequest {
397 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
398 ensure_protocol_version(self.protocol_version)?;
399 if self.draft.protocol_version != self.protocol_version {
400 return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
401 parent: "RemoteTriggerRegisterSubscriptionRequest",
402 child: "draft",
403 parent_version: self.protocol_version,
404 child_version: self.draft.protocol_version,
405 });
406 }
407 self.draft.validate()
408 }
409}
410
411#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
412pub struct RemoteTriggerRegisterSubscriptionResult {
413 pub protocol_version: u32,
414 pub record: RemoteTriggerSubscriptionRecord,
415}
416
417impl RemoteTriggerRegisterSubscriptionResult {
418 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
419 ensure_protocol_version(self.protocol_version)?;
420 self.record
421 .validate("RemoteTriggerRegisterSubscriptionResult")
422 }
423}
424
425#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
426pub struct RemoteTriggerListSubscriptionsResponse {
427 pub protocol_version: u32,
428 #[serde(default)]
429 pub subscriptions: Vec<RemoteTriggerSubscriptionRecord>,
430}
431
432impl RemoteTriggerListSubscriptionsResponse {
433 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
434 ensure_protocol_version(self.protocol_version)?;
435 for record in &self.subscriptions {
436 record.validate("RemoteTriggerListSubscriptionsResponse")?;
437 }
438 Ok(())
439 }
440}
441
442#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
443pub struct RemoteTriggerCancelSubscriptionRequest {
444 pub protocol_version: u32,
445 pub session_id: String,
446 pub handle: String,
447}
448
449impl RemoteTriggerCancelSubscriptionRequest {
450 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
451 ensure_protocol_version(self.protocol_version)?;
452 require_non_empty(
453 "RemoteTriggerCancelSubscriptionRequest",
454 "session_id",
455 &self.session_id,
456 )?;
457 require_non_empty(
458 "RemoteTriggerCancelSubscriptionRequest",
459 "handle",
460 &self.handle,
461 )
462 }
463}
464
465#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
466pub struct RemoteTriggerCancelSubscriptionResult {
467 pub protocol_version: u32,
468 pub session_id: String,
469 pub handle: String,
470 pub cancelled: bool,
471}
472
473impl RemoteTriggerCancelSubscriptionResult {
474 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
475 ensure_protocol_version(self.protocol_version)?;
476 require_non_empty(
477 "RemoteTriggerCancelSubscriptionResult",
478 "session_id",
479 &self.session_id,
480 )?;
481 require_non_empty(
482 "RemoteTriggerCancelSubscriptionResult",
483 "handle",
484 &self.handle,
485 )
486 }
487}