Skip to main content

fakecloud_sdk/
types.rs

1use serde::{Deserialize, Serialize};
2
3// ── Health ──────────────────────────────────────────────────────────
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(rename_all = "camelCase")]
7pub struct HealthResponse {
8    pub status: String,
9    pub version: String,
10    pub services: Vec<String>,
11}
12
13// ── Reset ───────────────────────────────────────────────────────────
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct ResetResponse {
18    pub status: String,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct ResetServiceResponse {
24    pub reset: String,
25}
26
27// ── RDS ─────────────────────────────────────────────────────────────
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub struct RdsTag {
32    pub key: String,
33    pub value: String,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct RdsInstance {
39    pub db_instance_identifier: String,
40    pub db_instance_arn: String,
41    pub db_instance_class: String,
42    pub engine: String,
43    pub engine_version: String,
44    pub db_instance_status: String,
45    pub master_username: String,
46    pub db_name: Option<String>,
47    pub endpoint_address: String,
48    pub port: i32,
49    pub allocated_storage: i32,
50    pub publicly_accessible: bool,
51    pub deletion_protection: bool,
52    pub created_at: String,
53    pub dbi_resource_id: String,
54    pub container_id: String,
55    pub host_port: u16,
56    pub tags: Vec<RdsTag>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct RdsInstancesResponse {
62    pub instances: Vec<RdsInstance>,
63}
64
65// ── Lambda ──────────────────────────────────────────────────────────
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(rename_all = "camelCase")]
69pub struct LambdaInvocation {
70    pub function_arn: String,
71    pub payload: String,
72    pub source: String,
73    pub timestamp: String,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct LambdaInvocationsResponse {
79    pub invocations: Vec<LambdaInvocation>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct WarmContainer {
85    pub function_name: String,
86    pub runtime: String,
87    pub container_id: String,
88    pub last_used_secs_ago: u64,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct WarmContainersResponse {
94    pub containers: Vec<WarmContainer>,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct EvictContainerResponse {
100    pub evicted: bool,
101}
102
103// ── SES ─────────────────────────────────────────────────────────────
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106#[serde(rename_all = "camelCase")]
107pub struct SentEmail {
108    pub message_id: String,
109    pub from: String,
110    pub to: Vec<String>,
111    #[serde(default)]
112    pub cc: Vec<String>,
113    #[serde(default)]
114    pub bcc: Vec<String>,
115    pub subject: Option<String>,
116    pub html_body: Option<String>,
117    pub text_body: Option<String>,
118    pub raw_data: Option<String>,
119    pub template_name: Option<String>,
120    pub template_data: Option<String>,
121    #[serde(default)]
122    pub dkim_signature: Option<String>,
123    /// Synthesized RFC 5322 headers stamped onto the message at send
124    /// time. When DKIM is on, the first entry is `DKIM-Signature`. Each
125    /// pair is `(name, value)`.
126    #[serde(default)]
127    pub headers: Vec<(String, String)>,
128    pub timestamp: String,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(rename_all = "camelCase")]
133pub struct SesEmailsResponse {
134    pub emails: Vec<SentEmail>,
135}
136
137/// Admin payload to flip an identity's `MailFromDomainStatus` for tests.
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub struct SesMailFromStatusRequest {
141    pub status: String,
142}
143
144// ── SES introspection: bounces / insights / SMTP submissions / event-dest ──
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct SesBouncedRecipientInfo {
149    pub recipient: String,
150    pub bounce_type: String,
151    pub action: String,
152    pub status: String,
153    pub diagnostic_code: String,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct SesBounce {
159    pub message_id: String,
160    pub bounce_type: String,
161    pub bounce_sub_type: String,
162    pub bounced_recipient_info: Vec<SesBouncedRecipientInfo>,
163    pub explanation: Option<String>,
164    pub timestamp: String,
165    pub original_message_id: String,
166    pub bounce_sender: String,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct SesBouncesResponse {
172    pub bounces: Vec<SesBounce>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub struct SesMessageInsightEvent {
178    pub destination: String,
179    pub timestamp: String,
180    #[serde(default, skip_serializing_if = "Option::is_none")]
181    pub bounce_type: Option<String>,
182    #[serde(default, skip_serializing_if = "Option::is_none")]
183    pub bounce_sub_type: Option<String>,
184    #[serde(default, skip_serializing_if = "Option::is_none")]
185    pub diagnostic_code: Option<String>,
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub complaint_feedback_type: Option<String>,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct SesMessageInsightsResponse {
193    pub message_id: String,
194    pub sends: Vec<SesMessageInsightEvent>,
195    pub deliveries: Vec<SesMessageInsightEvent>,
196    pub opens: Vec<SesMessageInsightEvent>,
197    pub clicks: Vec<SesMessageInsightEvent>,
198    pub bounces: Vec<SesMessageInsightEvent>,
199    pub complaints: Vec<SesMessageInsightEvent>,
200    pub rejects: Vec<SesMessageInsightEvent>,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct SesSmtpSubmission {
206    pub message_id: String,
207    pub from: String,
208    pub to: Vec<String>,
209    pub subject: Option<String>,
210    pub raw_size_bytes: usize,
211    pub received_at: String,
212    pub auth_user: String,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(rename_all = "camelCase")]
217pub struct SesSmtpSubmissionsResponse {
218    pub submissions: Vec<SesSmtpSubmission>,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
222#[serde(rename_all = "camelCase")]
223pub struct SesEventDestinationDelivery {
224    pub destination_name: String,
225    pub destination_type: String,
226    pub event_type: String,
227    pub message_id: String,
228    pub dispatched_at: String,
229    pub target_arn: String,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
233#[serde(rename_all = "camelCase")]
234pub struct SesEventDestinationDeliveriesResponse {
235    pub deliveries: Vec<SesEventDestinationDelivery>,
236}
237
238/// Admin payload to flip the SES account-level `production_access_enabled`
239/// flag. fakecloud defaults to `production_access_enabled=true` so users
240/// don't have to verify recipients to send mail; flip this to `false` to
241/// exercise sandbox-mode semantics (verified-recipient gate, send quotas,
242/// etc.).
243#[derive(Debug, Clone, Serialize, Deserialize)]
244#[serde(rename_all = "camelCase")]
245pub struct SesSandboxRequest {
246    /// `true` puts the account back into sandbox mode (production access
247    /// disabled); `false` re-enables production access.
248    pub sandbox: bool,
249}
250
251/// Admin payload for `/_fakecloud/logs/anomalies/inject`. Lets tests
252/// seed synthetic CloudWatch Logs anomalies so they can exercise
253/// `ListAnomalies` / `UpdateAnomaly` deterministically.
254#[derive(Debug, Clone, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256pub struct LogsAnomalyInjectRequest {
257    pub anomaly_detector_arn: String,
258    #[serde(default)]
259    pub log_group_arns: Vec<String>,
260    pub pattern_string: String,
261    #[serde(default)]
262    pub priority: Option<String>,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
266#[serde(rename_all = "camelCase")]
267pub struct LogsAnomalyInjectResponse {
268    pub anomaly_id: String,
269}
270
271/// One entry in the `/_fakecloud/logs/delivery-config` introspection
272/// response. Combines a `Delivery` with the `log_type` from its
273/// associated `DeliverySource` so test code can assert end-to-end
274/// configuration without joining state manually.
275#[derive(Debug, Clone, Serialize, Deserialize)]
276#[serde(rename_all = "camelCase")]
277pub struct LogsDeliveryConfiguration {
278    pub id: String,
279    /// Delivery identifier (same value as `id`; mirrors AWS naming).
280    pub name: String,
281    pub delivery_destination_arn: String,
282    pub delivery_source_name: String,
283    /// Log type from the associated `DeliverySource` (e.g. `ACCESS_LOGS`).
284    /// Empty string when the source has been deleted out from under the
285    /// delivery.
286    pub log_type: String,
287    #[serde(default)]
288    pub record_fields: Vec<String>,
289    #[serde(default)]
290    pub field_delimiter: Option<String>,
291    #[serde(default)]
292    pub s3_delivery_configuration: Option<serde_json::Value>,
293    /// Unix-ms timestamp of `CreateDelivery`. `0` for deliveries
294    /// recovered from older snapshots without this field.
295    pub created_at: i64,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
299#[serde(rename_all = "camelCase")]
300pub struct LogsDeliveryConfigResponse {
301    pub configurations: Vec<LogsDeliveryConfiguration>,
302}
303
304/// One `Fields` entry parsed from a log group's index policy document.
305#[derive(Debug, Clone, Serialize, Deserialize)]
306#[serde(rename_all = "camelCase")]
307pub struct LogsFieldIndex {
308    /// Fields list from `IndexPolicy.policy_document.Fields`.
309    pub fields: Vec<String>,
310    /// Unix-ms when the policy was created. Mirrors `last_updated_time`
311    /// since fakecloud doesn't track a separate creation timestamp.
312    pub created_at: i64,
313    /// Unix-ms when the policy was last touched
314    /// (PutIndexPolicy updates).
315    pub last_used_at: i64,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320pub struct LogsFieldIndexesResponse {
321    pub log_group_name: String,
322    pub indexes: Vec<LogsFieldIndex>,
323}
324
325/// Admin payload for `/_fakecloud/cognito/compromised-passwords`.
326/// Plaintext passwords are hashed (sha256) and added to the
327/// compromised-credentials set consulted by `InitiateAuth` /
328/// `AdminInitiateAuth` when the pool's
329/// `CompromisedCredentialsRiskConfiguration.Actions.EventAction` is
330/// `BLOCK`.
331#[derive(Debug, Clone, Serialize, Deserialize)]
332#[serde(rename_all = "camelCase")]
333pub struct CognitoCompromisedPasswordsRequest {
334    pub passwords: Vec<String>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
338#[serde(rename_all = "camelCase")]
339pub struct InboundEmailRequest {
340    pub from: String,
341    pub to: Vec<String>,
342    pub subject: String,
343    pub body: String,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347#[serde(rename_all = "camelCase")]
348pub struct InboundActionExecuted {
349    pub rule: String,
350    pub action_type: String,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
354#[serde(rename_all = "camelCase")]
355pub struct InboundEmailResponse {
356    pub message_id: String,
357    pub matched_rules: Vec<String>,
358    pub actions_executed: Vec<InboundActionExecuted>,
359}
360
361// ── SNS ─────────────────────────────────────────────────────────────
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
364#[serde(rename_all = "camelCase")]
365pub struct SnsMessage {
366    pub message_id: String,
367    pub topic_arn: String,
368    pub message: String,
369    pub subject: Option<String>,
370    pub timestamp: String,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
374#[serde(rename_all = "camelCase")]
375pub struct SnsMessagesResponse {
376    pub messages: Vec<SnsMessage>,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
380#[serde(rename_all = "camelCase")]
381pub struct SnsSmsMessage {
382    pub phone_number: String,
383    pub message: String,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388pub struct SnsSmsResponse {
389    pub messages: Vec<SnsSmsMessage>,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
393#[serde(rename_all = "camelCase")]
394pub struct PendingConfirmation {
395    pub subscription_arn: String,
396    pub topic_arn: String,
397    pub protocol: String,
398    pub endpoint: String,
399    pub token: Option<String>,
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize)]
403#[serde(rename_all = "camelCase")]
404pub struct PendingConfirmationsResponse {
405    pub pending_confirmations: Vec<PendingConfirmation>,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize)]
409#[serde(rename_all = "camelCase")]
410pub struct ConfirmSubscriptionRequest {
411    pub subscription_arn: String,
412}
413
414#[derive(Debug, Clone, Serialize, Deserialize)]
415#[serde(rename_all = "camelCase")]
416pub struct ConfirmSubscriptionResponse {
417    pub confirmed: bool,
418}
419
420// ── SQS ─────────────────────────────────────────────────────────────
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
423#[serde(rename_all = "camelCase")]
424pub struct SqsMessageInfo {
425    pub message_id: String,
426    pub body: String,
427    pub receive_count: u64,
428    pub in_flight: bool,
429    pub created_at: String,
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
433#[serde(rename_all = "camelCase")]
434pub struct SqsQueueMessages {
435    pub queue_url: String,
436    pub queue_name: String,
437    pub messages: Vec<SqsMessageInfo>,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
441#[serde(rename_all = "camelCase")]
442pub struct SqsMessagesResponse {
443    pub queues: Vec<SqsQueueMessages>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
447#[serde(rename_all = "camelCase")]
448pub struct ExpirationTickResponse {
449    pub expired_messages: u64,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
453#[serde(rename_all = "camelCase")]
454pub struct ForceDlqResponse {
455    pub moved_messages: u64,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
459#[serde(rename_all = "camelCase")]
460pub struct AppAsTickResponse {
461    /// Number of scaling decisions that were applied this tick.
462    pub applied: usize,
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(rename_all = "camelCase")]
467pub struct AppAsScheduledTickResponse {
468    /// Number of scheduled actions that fired this tick.
469    pub fired: usize,
470}
471
472#[derive(Debug, Clone, Serialize, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct SetSsmCommandStatusRequest {
475    pub account_id: Option<String>,
476    pub status: String,
477}
478
479#[derive(Debug, Clone, Serialize, Deserialize)]
480#[serde(rename_all = "camelCase")]
481pub struct SetSsmCommandStatusResponse {
482    pub updated: bool,
483}
484
485#[derive(Debug, Clone, Default, Serialize, Deserialize)]
486#[serde(rename_all = "camelCase")]
487pub struct FailSsmCommandRequest {
488    pub account_id: Option<String>,
489    /// Optional: target a single invocation. When `None`, every
490    /// invocation on the command is flipped to `Failed`.
491    pub instance_id: Option<String>,
492    /// Optional friendly status detail (e.g. "Script exited with code 7").
493    /// Defaults to "Failed".
494    pub status_details: Option<String>,
495    /// Optional captured stderr to expose via `GetCommandInvocation`.
496    pub standard_error_content: Option<String>,
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize)]
500#[serde(rename_all = "camelCase")]
501pub struct FailSsmCommandResponse {
502    pub updated_invocations: usize,
503}
504
505/// One emitted parameter-policy event, as recorded by the
506/// `/_fakecloud/ssm/parameter-policy-events` admin endpoint.
507#[derive(Debug, Clone, Serialize, Deserialize)]
508#[serde(rename_all = "camelCase")]
509pub struct SsmParameterPolicyEvent {
510    pub parameter_name: String,
511    pub parameter_arn: String,
512    /// One of `ExpirationRegistered`, `ExpirationNotificationRegistered`,
513    /// `NoChangeNotificationRegistered`, `Expiration`,
514    /// `ExpirationNotification`, `NoChangeNotification`.
515    pub event_type: String,
516    pub message: String,
517    pub created_at: String,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize)]
521#[serde(rename_all = "camelCase")]
522pub struct SsmParameterPolicyEventsResponse {
523    pub events: Vec<SsmParameterPolicyEvent>,
524}
525
526/// Body shape for `POST /_fakecloud/ssm/sessions/inject`. Drops a fake
527/// session record into state without going through StartSession (which
528/// returns the Smithy-declared `TargetNotConnected` unless
529/// `FAKECLOUD_SSM_SESSION_ECHO=1`). Lets tests assert
530/// `DescribeSessions`/`TerminateSession` paths work end-to-end.
531#[derive(Debug, Clone, Default, Serialize, Deserialize)]
532#[serde(rename_all = "camelCase")]
533pub struct InjectSsmSessionRequest {
534    pub account_id: Option<String>,
535    pub target: String,
536    /// Defaults to `Connected`; pass `Terminated` to seed a finished
537    /// session.
538    pub status: Option<String>,
539    /// Defaults to the account-root IAM ARN.
540    pub owner: Option<String>,
541    pub reason: Option<String>,
542    /// Optional explicit session ID. Falls back to the autogenerated
543    /// `session-XXXXXXXXXXXX` form when omitted or empty.
544    pub session_id: Option<String>,
545}
546
547#[derive(Debug, Clone, Serialize, Deserialize)]
548#[serde(rename_all = "camelCase")]
549pub struct InjectSsmSessionResponse {
550    pub session_id: String,
551}
552
553// ── EventBridge ─────────────────────────────────────────────────────
554
555#[derive(Debug, Clone, Serialize, Deserialize)]
556#[serde(rename_all = "camelCase")]
557pub struct EventBridgeEvent {
558    pub event_id: String,
559    pub source: String,
560    pub detail_type: String,
561    pub detail: String,
562    pub bus_name: String,
563    pub timestamp: String,
564}
565
566#[derive(Debug, Clone, Serialize, Deserialize)]
567#[serde(rename_all = "camelCase")]
568pub struct EventBridgeLambdaDelivery {
569    pub function_arn: String,
570    pub payload: String,
571    pub timestamp: String,
572}
573
574#[derive(Debug, Clone, Serialize, Deserialize)]
575#[serde(rename_all = "camelCase")]
576pub struct EventBridgeLogDelivery {
577    pub log_group_arn: String,
578    pub payload: String,
579    pub timestamp: String,
580}
581
582#[derive(Debug, Clone, Serialize, Deserialize)]
583#[serde(rename_all = "camelCase")]
584pub struct EventBridgeDeliveries {
585    pub lambda: Vec<EventBridgeLambdaDelivery>,
586    pub logs: Vec<EventBridgeLogDelivery>,
587}
588
589#[derive(Debug, Clone, Serialize, Deserialize)]
590#[serde(rename_all = "camelCase")]
591pub struct EventHistoryResponse {
592    pub events: Vec<EventBridgeEvent>,
593    pub deliveries: EventBridgeDeliveries,
594}
595
596#[derive(Debug, Clone, Serialize, Deserialize)]
597#[serde(rename_all = "camelCase")]
598pub struct FireRuleRequest {
599    pub bus_name: Option<String>,
600    pub rule_name: String,
601}
602
603// ── RDS aws_lambda extension bridge ─────────────────────────────────
604
605/// Request body for `POST /_fakecloud/rds/lambda-invoke`. The endpoint is
606/// the bridge that the PostgreSQL `aws_lambda` extension calls into from
607/// inside an RDS DB instance container — it's normally not driven by
608/// user code directly.
609#[derive(Debug, Clone, Serialize, Deserialize)]
610#[serde(rename_all = "snake_case")]
611pub struct RdsLambdaInvokeRequest {
612    pub function_name: String,
613    pub payload: Option<serde_json::Value>,
614    pub invocation_type: Option<String>,
615    pub region: Option<String>,
616}
617
618/// Shape returned by the bridge — mirrors what `aws_lambda.invoke()`
619/// returns to SQL callers (RDS/Aurora-compatible).
620#[derive(Debug, Clone, Serialize, Deserialize)]
621#[serde(rename_all = "snake_case")]
622pub struct RdsLambdaInvokeResponse {
623    pub status_code: i32,
624    pub payload: Option<serde_json::Value>,
625    pub executed_version: Option<String>,
626    pub log_result: Option<String>,
627}
628
629// ── RDS aws_s3 extension bridge ─────────────────────────────────────
630
631/// Request body for `POST /_fakecloud/rds/s3-import`. The endpoint is
632/// the bridge that the PostgreSQL `aws_s3` extension calls into to
633/// fetch an object from a fakecloud bucket. Body is returned base64
634/// encoded so JSON transport stays text-only.
635#[derive(Debug, Clone, Serialize, Deserialize)]
636#[serde(rename_all = "snake_case")]
637pub struct RdsS3ImportRequest {
638    pub bucket: String,
639    pub key: String,
640    pub region: Option<String>,
641}
642
643#[derive(Debug, Clone, Serialize, Deserialize)]
644#[serde(rename_all = "snake_case")]
645pub struct RdsS3ImportResponse {
646    pub bucket: String,
647    pub key: String,
648    pub body_b64: String,
649    pub bytes_processed: i64,
650}
651
652/// Request body for `POST /_fakecloud/rds/s3-export`. Bridge equivalent
653/// of an S3 PutObject driven from inside the DB container.
654#[derive(Debug, Clone, Serialize, Deserialize)]
655#[serde(rename_all = "snake_case")]
656pub struct RdsS3ExportRequest {
657    pub bucket: String,
658    pub key: String,
659    pub region: Option<String>,
660    pub body_b64: String,
661}
662
663#[derive(Debug, Clone, Serialize, Deserialize)]
664#[serde(rename_all = "snake_case")]
665pub struct RdsS3ExportResponse {
666    pub bucket: String,
667    pub key: String,
668    pub bytes_uploaded: i64,
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
672#[serde(rename_all = "camelCase")]
673pub struct FireRuleTarget {
674    #[serde(rename = "type")]
675    pub target_type: String,
676    pub arn: String,
677}
678
679#[derive(Debug, Clone, Serialize, Deserialize)]
680#[serde(rename_all = "camelCase")]
681pub struct FireRuleResponse {
682    pub targets: Vec<FireRuleTarget>,
683}
684
685// ── Scheduler (EventBridge Scheduler) ───────────────────────────────
686
687#[derive(Debug, Clone, Serialize, Deserialize)]
688#[serde(rename_all = "camelCase")]
689pub struct SchedulerSchedule {
690    pub account_id: String,
691    pub group_name: String,
692    pub name: String,
693    pub arn: String,
694    pub state: String,
695    pub schedule_expression: String,
696    pub target_arn: String,
697    pub last_fired: Option<String>,
698}
699
700#[derive(Debug, Clone, Serialize, Deserialize)]
701#[serde(rename_all = "camelCase")]
702pub struct SchedulerSchedulesResponse {
703    pub schedules: Vec<SchedulerSchedule>,
704}
705
706#[derive(Debug, Clone, Serialize, Deserialize)]
707#[serde(rename_all = "camelCase")]
708pub struct FireScheduleResponse {
709    pub schedule_arn: String,
710    pub target_arn: String,
711}
712
713// ── S3 ──────────────────────────────────────────────────────────────
714
715#[derive(Debug, Clone, Serialize, Deserialize)]
716#[serde(rename_all = "camelCase")]
717pub struct S3Notification {
718    pub bucket: String,
719    pub key: String,
720    pub event_type: String,
721    pub timestamp: String,
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
725#[serde(rename_all = "camelCase")]
726pub struct S3NotificationsResponse {
727    pub notifications: Vec<S3Notification>,
728}
729
730#[derive(Debug, Clone, Serialize, Deserialize)]
731#[serde(rename_all = "camelCase")]
732pub struct LifecycleTickResponse {
733    pub processed_buckets: u64,
734    pub expired_objects: u64,
735    pub transitioned_objects: u64,
736}
737
738#[derive(Debug, Clone, Serialize, Deserialize)]
739#[serde(rename_all = "camelCase")]
740pub struct S3AccessPointEntry {
741    pub name: String,
742    pub alias: String,
743    pub bucket: String,
744    pub account_id: String,
745    pub network_origin: String,
746    #[serde(skip_serializing_if = "Option::is_none")]
747    pub vpc_configuration: Option<String>,
748    #[serde(skip_serializing_if = "Option::is_none")]
749    pub public_access_block: Option<String>,
750    pub created_at: String,
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize)]
754#[serde(rename_all = "camelCase")]
755pub struct S3AccessPointsResponse {
756    pub access_points: Vec<S3AccessPointEntry>,
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
760#[serde(rename_all = "camelCase")]
761pub struct S3ObjectLambdaResponse {
762    pub request_token: String,
763    pub request_route: String,
764    #[serde(skip_serializing_if = "Option::is_none")]
765    pub status_code: Option<u16>,
766    pub body_base64: String,
767    pub body_size: u64,
768    #[serde(skip_serializing_if = "Option::is_none")]
769    pub content_type: Option<String>,
770    #[serde(skip_serializing_if = "Option::is_none")]
771    pub error_message: Option<String>,
772    pub metadata: std::collections::BTreeMap<String, String>,
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize)]
776#[serde(rename_all = "camelCase")]
777pub struct S3ObjectLambdaResponsesResponse {
778    pub responses: Vec<S3ObjectLambdaResponse>,
779}
780
781// ── DynamoDB ────────────────────────────────────────────────────────
782
783#[derive(Debug, Clone, Serialize, Deserialize)]
784#[serde(rename_all = "camelCase")]
785pub struct TtlTickResponse {
786    pub expired_items: u64,
787}
788
789// ── SecretsManager ──────────────────────────────────────────────────
790
791#[derive(Debug, Clone, Serialize, Deserialize)]
792#[serde(rename_all = "camelCase")]
793pub struct RotationTickResponse {
794    pub rotated_secrets: Vec<String>,
795}
796
797// ── ElastiCache ─────────────────────────────────────────────────────
798
799#[derive(Debug, Clone, Serialize, Deserialize)]
800#[serde(rename_all = "camelCase")]
801pub struct ElastiCacheCluster {
802    pub cache_cluster_id: String,
803    pub cache_cluster_status: String,
804    pub engine: String,
805    pub engine_version: String,
806    pub cache_node_type: String,
807    pub num_cache_nodes: i32,
808    pub replication_group_id: Option<String>,
809    pub port: Option<i32>,
810    pub host_port: Option<u16>,
811    pub container_id: Option<String>,
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize)]
815#[serde(rename_all = "camelCase")]
816pub struct ElastiCacheClustersResponse {
817    pub clusters: Vec<ElastiCacheCluster>,
818}
819
820#[derive(Debug, Clone, Serialize, Deserialize)]
821#[serde(rename_all = "camelCase")]
822pub struct ElastiCacheReplicationGroupIntrospection {
823    pub replication_group_id: String,
824    pub status: String,
825    pub description: String,
826    pub member_clusters: Vec<String>,
827    pub automatic_failover: bool,
828    pub multi_az: bool,
829    pub engine: String,
830    pub engine_version: String,
831    pub cache_node_type: String,
832    pub num_cache_clusters: i32,
833}
834
835#[derive(Debug, Clone, Serialize, Deserialize)]
836#[serde(rename_all = "camelCase")]
837pub struct ElastiCacheReplicationGroupsResponse {
838    pub replication_groups: Vec<ElastiCacheReplicationGroupIntrospection>,
839}
840
841#[derive(Debug, Clone, Serialize, Deserialize)]
842#[serde(rename_all = "camelCase")]
843pub struct ElastiCacheServerlessCacheIntrospection {
844    pub serverless_cache_name: String,
845    pub status: String,
846    pub engine: String,
847    pub engine_version: String,
848    pub cache_node_type: Option<String>,
849}
850
851#[derive(Debug, Clone, Serialize, Deserialize)]
852#[serde(rename_all = "camelCase")]
853pub struct ElastiCacheServerlessCachesResponse {
854    pub serverless_caches: Vec<ElastiCacheServerlessCacheIntrospection>,
855}
856
857#[derive(Debug, Clone, Serialize, Deserialize)]
858#[serde(rename_all = "camelCase")]
859pub struct ElastiCacheAclUser {
860    pub name: String,
861    pub status: String,
862    pub access_string: String,
863    pub no_password_required: bool,
864    pub password_count: i32,
865}
866
867#[derive(Debug, Clone, Serialize, Deserialize)]
868#[serde(rename_all = "camelCase")]
869pub struct ElastiCacheAclGroup {
870    pub name: String,
871    pub members: Vec<String>,
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize)]
875#[serde(rename_all = "camelCase")]
876pub struct ElastiCacheAclCluster {
877    pub cluster_id: String,
878    pub engine: String,
879    pub users: Vec<ElastiCacheAclUser>,
880    pub groups: Vec<ElastiCacheAclGroup>,
881}
882
883#[derive(Debug, Clone, Serialize, Deserialize)]
884#[serde(rename_all = "camelCase")]
885pub struct ElastiCacheAclsResponse {
886    pub acls: Vec<ElastiCacheAclCluster>,
887}
888
889// ── Step Functions ──────────────────────────────────────────────────
890
891#[derive(Debug, Clone, Serialize, Deserialize)]
892#[serde(rename_all = "camelCase")]
893pub struct StepFunctionsExecution {
894    pub execution_arn: String,
895    pub state_machine_arn: String,
896    pub name: String,
897    pub status: String,
898    #[serde(skip_serializing_if = "Option::is_none")]
899    pub input: Option<String>,
900    #[serde(skip_serializing_if = "Option::is_none")]
901    pub output: Option<String>,
902    pub start_date: String,
903    #[serde(skip_serializing_if = "Option::is_none")]
904    pub stop_date: Option<String>,
905}
906
907#[derive(Debug, Clone, Serialize, Deserialize)]
908#[serde(rename_all = "camelCase")]
909pub struct StepFunctionsExecutionsResponse {
910    pub executions: Vec<StepFunctionsExecution>,
911}
912
913#[derive(Debug, Clone, Serialize, Deserialize)]
914#[serde(rename_all = "camelCase")]
915pub struct StepFunctionsSyncBillingDetails {
916    pub billed_duration_in_milliseconds: i64,
917    pub billed_memory_used_in_mb: i64,
918}
919
920#[derive(Debug, Clone, Serialize, Deserialize)]
921#[serde(rename_all = "camelCase")]
922pub struct StepFunctionsSyncExecution {
923    pub execution_arn: String,
924    pub state_machine_arn: String,
925    pub name: String,
926    pub status: String,
927    #[serde(skip_serializing_if = "Option::is_none")]
928    pub input: Option<String>,
929    #[serde(skip_serializing_if = "Option::is_none")]
930    pub output: Option<String>,
931    pub started_at: String,
932    #[serde(skip_serializing_if = "Option::is_none")]
933    pub stopped_at: Option<String>,
934    pub duration_ms: i64,
935    pub billing_details: StepFunctionsSyncBillingDetails,
936}
937
938#[derive(Debug, Clone, Serialize, Deserialize)]
939#[serde(rename_all = "camelCase")]
940pub struct StepFunctionsSyncExecutionsResponse {
941    pub executions: Vec<StepFunctionsSyncExecution>,
942}
943
944#[derive(Debug, Clone, Serialize, Deserialize)]
945#[serde(rename_all = "camelCase")]
946pub struct StepFunctionsExecutionTreeNode {
947    pub arn: String,
948    pub state_machine_arn: String,
949    pub status: String,
950    pub started_at: String,
951    #[serde(skip_serializing_if = "Option::is_none")]
952    pub stopped_at: Option<String>,
953    pub children: Vec<StepFunctionsExecutionTreeNode>,
954}
955
956#[derive(Debug, Clone, Serialize, Deserialize)]
957#[serde(rename_all = "camelCase")]
958pub struct StepFunctionsExecutionTreeResponse {
959    pub root_arn: String,
960    pub tree: StepFunctionsExecutionTreeNode,
961}
962
963#[derive(Debug, Clone, Serialize, Deserialize, Default)]
964#[serde(rename_all = "camelCase")]
965pub struct SfnEnqueueActivityTaskRequest {
966    pub activity_arn: String,
967    #[serde(skip_serializing_if = "Option::is_none")]
968    pub input: Option<String>,
969    #[serde(skip_serializing_if = "Option::is_none")]
970    pub heartbeat_seconds: Option<i64>,
971    #[serde(skip_serializing_if = "Option::is_none")]
972    pub timeout_seconds: Option<i64>,
973}
974
975#[derive(Debug, Clone, Serialize, Deserialize)]
976#[serde(rename_all = "camelCase")]
977pub struct SfnEnqueueActivityTaskResponse {
978    pub task_token: String,
979}
980
981// ── Cognito ─────────────────────────────────────────────────────────
982
983#[derive(Debug, Clone, Serialize, Deserialize)]
984#[serde(rename_all = "camelCase")]
985pub struct UserConfirmationCodes {
986    pub confirmation_code: Option<String>,
987    pub attribute_verification_codes: serde_json::Value,
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize)]
991#[serde(rename_all = "camelCase")]
992pub struct ConfirmationCode {
993    pub pool_id: String,
994    pub username: String,
995    pub code: String,
996    #[serde(rename = "type")]
997    pub code_type: String,
998    #[serde(skip_serializing_if = "Option::is_none")]
999    pub attribute: Option<String>,
1000}
1001
1002#[derive(Debug, Clone, Serialize, Deserialize)]
1003#[serde(rename_all = "camelCase")]
1004pub struct ConfirmationCodesResponse {
1005    pub codes: Vec<ConfirmationCode>,
1006}
1007
1008#[derive(Debug, Clone, Serialize, Deserialize)]
1009#[serde(rename_all = "camelCase")]
1010pub struct ConfirmUserRequest {
1011    pub user_pool_id: String,
1012    pub username: String,
1013}
1014
1015#[derive(Debug, Clone, Serialize, Deserialize)]
1016#[serde(rename_all = "camelCase")]
1017pub struct ConfirmUserResponse {
1018    pub confirmed: bool,
1019    #[serde(skip_serializing_if = "Option::is_none")]
1020    pub error: Option<String>,
1021}
1022
1023#[derive(Debug, Clone, Serialize, Deserialize)]
1024#[serde(rename_all = "camelCase")]
1025pub struct TokenInfo {
1026    #[serde(rename = "type")]
1027    pub token_type: String,
1028    pub username: String,
1029    pub pool_id: String,
1030    pub client_id: String,
1031    pub issued_at: f64,
1032}
1033
1034#[derive(Debug, Clone, Serialize, Deserialize)]
1035#[serde(rename_all = "camelCase")]
1036pub struct TokensResponse {
1037    pub tokens: Vec<TokenInfo>,
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize)]
1041#[serde(rename_all = "camelCase")]
1042pub struct ExpireTokensRequest {
1043    #[serde(skip_serializing_if = "Option::is_none")]
1044    pub user_pool_id: Option<String>,
1045    #[serde(skip_serializing_if = "Option::is_none")]
1046    pub username: Option<String>,
1047}
1048
1049#[derive(Debug, Clone, Serialize, Deserialize)]
1050#[serde(rename_all = "camelCase")]
1051pub struct ExpireTokensResponse {
1052    pub expired_tokens: u64,
1053}
1054
1055#[derive(Debug, Clone, Serialize, Deserialize)]
1056#[serde(rename_all = "camelCase")]
1057pub struct AuthEvent {
1058    pub event_type: String,
1059    pub username: String,
1060    pub user_pool_id: String,
1061    pub client_id: Option<String>,
1062    pub timestamp: f64,
1063    pub success: bool,
1064}
1065
1066#[derive(Debug, Clone, Serialize, Deserialize)]
1067#[serde(rename_all = "camelCase")]
1068pub struct AuthEventsResponse {
1069    pub events: Vec<AuthEvent>,
1070}
1071
1072/// One PreTokenGeneration Lambda trigger invocation captured for
1073/// introspection at `/_fakecloud/cognito/pretokengen/invocations`.
1074/// `claims_added` / `claims_overridden` / `group_overrides` are
1075/// pre-parsed from the Lambda response so test callers don't have to
1076/// walk the raw `claimsAndScopeOverrideDetails` shape themselves.
1077#[derive(Debug, Clone, Serialize, Deserialize)]
1078#[serde(rename_all = "camelCase")]
1079pub struct PreTokenGenInvocation {
1080    pub pool_id: String,
1081    pub user_pool_arn: String,
1082    pub username: String,
1083    pub trigger_source: String,
1084    pub lambda_arn: String,
1085    pub request_payload: serde_json::Value,
1086    pub response_payload: Option<serde_json::Value>,
1087    pub claims_added: Vec<String>,
1088    pub claims_overridden: Vec<String>,
1089    pub group_overrides: Vec<String>,
1090    /// RFC3339 timestamp.
1091    pub invoked_at: String,
1092    pub duration_ms: u64,
1093}
1094
1095#[derive(Debug, Clone, Serialize, Deserialize)]
1096#[serde(rename_all = "camelCase")]
1097pub struct PreTokenGenInvocationsResponse {
1098    pub invocations: Vec<PreTokenGenInvocation>,
1099}
1100
1101/// Request body for the `/_fakecloud/cognito/authorization-codes` admin
1102/// mint endpoint. Lets test harnesses (and any caller that wants to
1103/// drive the `authorization_code` grant before the Y4 hosted-UI lands)
1104/// pre-allocate the same `(client_id, redirect_uri, scopes, PKCE)`
1105/// binding the real `/oauth2/authorize` endpoint will eventually
1106/// produce.
1107#[derive(Debug, Clone, Serialize, Deserialize)]
1108#[serde(rename_all = "camelCase")]
1109pub struct MintAuthorizationCodeRequest {
1110    pub user_pool_id: String,
1111    pub client_id: String,
1112    pub username: String,
1113    pub redirect_uri: String,
1114    #[serde(default)]
1115    pub scopes: Vec<String>,
1116    #[serde(skip_serializing_if = "Option::is_none")]
1117    pub code_challenge: Option<String>,
1118    #[serde(skip_serializing_if = "Option::is_none")]
1119    pub code_challenge_method: Option<String>,
1120    #[serde(skip_serializing_if = "Option::is_none")]
1121    pub nonce: Option<String>,
1122}
1123
1124#[derive(Debug, Clone, Serialize, Deserialize)]
1125#[serde(rename_all = "camelCase")]
1126pub struct MintAuthorizationCodeResponse {
1127    pub code: String,
1128}
1129
1130// ── API Gateway v2 ──────────────────────────────────────────────────
1131
1132#[derive(Debug, Clone, Serialize, Deserialize)]
1133#[serde(rename_all = "camelCase")]
1134pub struct ApiGatewayV2Request {
1135    pub request_id: String,
1136    pub api_id: String,
1137    pub stage: String,
1138    pub method: String,
1139    pub path: String,
1140    pub headers: std::collections::HashMap<String, String>,
1141    pub query_params: std::collections::HashMap<String, String>,
1142    #[serde(skip_serializing_if = "Option::is_none")]
1143    pub body: Option<String>,
1144    pub timestamp: String,
1145    pub status_code: u16,
1146}
1147
1148#[derive(Debug, Clone, Serialize, Deserialize)]
1149#[serde(rename_all = "camelCase")]
1150pub struct ApiGatewayV2RequestsResponse {
1151    pub requests: Vec<ApiGatewayV2Request>,
1152}
1153
1154// ── Bedrock ────────────────────────────────────────────────────────
1155
1156#[derive(Debug, Clone, Serialize, Deserialize)]
1157#[serde(rename_all = "camelCase")]
1158pub struct BedrockInvocation {
1159    pub model_id: String,
1160    pub input: String,
1161    pub output: String,
1162    pub timestamp: String,
1163    /// Error detail for faulted calls, or `None` on success.
1164    #[serde(default)]
1165    pub error: Option<String>,
1166}
1167
1168#[derive(Debug, Clone, Serialize, Deserialize)]
1169#[serde(rename_all = "camelCase")]
1170pub struct BedrockInvocationsResponse {
1171    pub invocations: Vec<BedrockInvocation>,
1172}
1173
1174#[derive(Debug, Clone, Serialize, Deserialize)]
1175#[serde(rename_all = "camelCase")]
1176pub struct BedrockModelResponseConfig {
1177    pub status: String,
1178    pub model_id: String,
1179}
1180
1181/// One rule in a per-model response rule list.
1182///
1183/// `prompt_contains` is a substring that must appear in the prompt for this
1184/// rule to match. `None` or an empty string matches any prompt.
1185#[derive(Debug, Clone, Serialize, Deserialize)]
1186#[serde(rename_all = "camelCase")]
1187pub struct BedrockResponseRule {
1188    #[serde(default, skip_serializing_if = "Option::is_none")]
1189    pub prompt_contains: Option<String>,
1190    pub response: String,
1191}
1192
1193/// Configuration for a fault to inject on Bedrock runtime calls.
1194#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1195#[serde(rename_all = "camelCase")]
1196pub struct BedrockFaultRule {
1197    pub error_type: String,
1198    #[serde(default, skip_serializing_if = "Option::is_none")]
1199    pub message: Option<String>,
1200    #[serde(default, skip_serializing_if = "Option::is_none")]
1201    pub http_status: Option<u16>,
1202    #[serde(default, skip_serializing_if = "Option::is_none")]
1203    pub count: Option<u32>,
1204    #[serde(default, skip_serializing_if = "Option::is_none")]
1205    pub model_id: Option<String>,
1206    #[serde(default, skip_serializing_if = "Option::is_none")]
1207    pub operation: Option<String>,
1208}
1209
1210/// Server-side view of a queued fault rule.
1211#[derive(Debug, Clone, Serialize, Deserialize)]
1212#[serde(rename_all = "camelCase")]
1213pub struct BedrockFaultRuleState {
1214    pub error_type: String,
1215    pub message: String,
1216    pub http_status: u16,
1217    pub remaining: u32,
1218    #[serde(default)]
1219    pub model_id: Option<String>,
1220    #[serde(default)]
1221    pub operation: Option<String>,
1222}
1223
1224#[derive(Debug, Clone, Serialize, Deserialize)]
1225#[serde(rename_all = "camelCase")]
1226pub struct BedrockFaultsResponse {
1227    pub faults: Vec<BedrockFaultRuleState>,
1228}
1229
1230#[derive(Debug, Clone, Serialize, Deserialize)]
1231#[serde(rename_all = "camelCase")]
1232pub struct BedrockStatusResponse {
1233    pub status: String,
1234}
1235
1236#[derive(Debug, Clone, Serialize, Deserialize)]
1237#[serde(rename_all = "camelCase")]
1238pub struct BedrockAgentAliasSummary {
1239    pub alias_id: String,
1240    pub alias_name: String,
1241    pub agent_version: String,
1242    pub alias_arn: String,
1243    pub status: String,
1244    pub created_at: String,
1245    pub updated_at: String,
1246}
1247
1248#[derive(Debug, Clone, Serialize, Deserialize)]
1249#[serde(rename_all = "camelCase")]
1250pub struct BedrockAgentVersionSummary {
1251    pub agent_version: String,
1252    pub created_at: String,
1253    pub instruction: Option<String>,
1254    pub foundation_model: Option<String>,
1255}
1256
1257#[derive(Debug, Clone, Serialize, Deserialize)]
1258#[serde(rename_all = "camelCase")]
1259pub struct BedrockAgentKnowledgeBaseSummary {
1260    pub knowledge_base_id: String,
1261    pub state: String,
1262    pub description: Option<String>,
1263}
1264
1265#[derive(Debug, Clone, Serialize, Deserialize)]
1266#[serde(rename_all = "camelCase")]
1267pub struct BedrockAgentCollaboratorSummary {
1268    pub collaborator_id: String,
1269    pub collaborator_name: String,
1270    pub collaborator_alias_arn: String,
1271    pub relay_conversation_history: String,
1272}
1273
1274#[derive(Debug, Clone, Serialize, Deserialize)]
1275#[serde(rename_all = "camelCase")]
1276pub struct BedrockAgentRow {
1277    pub agent_id: String,
1278    pub agent_name: String,
1279    pub agent_arn: String,
1280    pub agent_status: String,
1281    pub foundation_model: Option<String>,
1282    pub instruction: Option<String>,
1283    pub knowledge_bases: Vec<BedrockAgentKnowledgeBaseSummary>,
1284    pub action_groups: Vec<serde_json::Value>,
1285    pub collaborators: Vec<BedrockAgentCollaboratorSummary>,
1286    pub aliases: Vec<BedrockAgentAliasSummary>,
1287    pub versions: Vec<BedrockAgentVersionSummary>,
1288    pub prompt_overrides: Option<serde_json::Value>,
1289    pub created_at: String,
1290    pub updated_at: String,
1291}
1292
1293#[derive(Debug, Clone, Serialize, Deserialize)]
1294#[serde(rename_all = "camelCase")]
1295pub struct BedrockAgentAgentsResponse {
1296    pub agents: Vec<BedrockAgentRow>,
1297}
1298
1299#[derive(Debug, Clone, Serialize, Deserialize)]
1300#[serde(rename_all = "camelCase")]
1301pub struct BedrockAgentRuntimeInvocation {
1302    pub invocation_id: String,
1303    pub op: String,
1304    pub agent_id: Option<String>,
1305    pub flow_id: Option<String>,
1306    pub session_id: Option<String>,
1307    pub input: String,
1308    pub output: String,
1309    pub output_chunks: u32,
1310    pub trace: Option<serde_json::Value>,
1311    #[serde(default)]
1312    pub citations: Vec<serde_json::Value>,
1313    pub invoked_at: String,
1314    pub duration_ms: u64,
1315}
1316
1317#[derive(Debug, Clone, Serialize, Deserialize)]
1318#[serde(rename_all = "camelCase")]
1319pub struct BedrockAgentRuntimeInvocationsResponse {
1320    pub invocations: Vec<BedrockAgentRuntimeInvocation>,
1321}
1322
1323#[derive(Debug, Clone, Serialize, Deserialize)]
1324#[serde(rename_all = "camelCase")]
1325pub struct EcrRepository {
1326    pub repository_name: String,
1327    pub repository_arn: String,
1328    pub registry_id: String,
1329    pub repository_uri: String,
1330    pub image_tag_mutability: String,
1331    pub scan_on_push: bool,
1332    pub created_at: String,
1333    pub tags: Vec<EcrTag>,
1334    pub has_policy: bool,
1335    pub has_lifecycle_policy: bool,
1336    pub image_count: u64,
1337    pub layer_count: u64,
1338}
1339
1340#[derive(Debug, Clone, Serialize, Deserialize)]
1341#[serde(rename_all = "camelCase")]
1342pub struct EcrImage {
1343    pub repository_name: String,
1344    pub image_digest: String,
1345    pub image_tags: Vec<String>,
1346    pub image_size_in_bytes: u64,
1347    pub image_manifest_media_type: String,
1348    pub image_pushed_at: String,
1349}
1350
1351#[derive(Debug, Clone, Serialize, Deserialize)]
1352#[serde(rename_all = "camelCase")]
1353pub struct EcrImagesResponse {
1354    pub images: Vec<EcrImage>,
1355}
1356
1357#[derive(Debug, Clone, Serialize, Deserialize)]
1358#[serde(rename_all = "camelCase")]
1359pub struct EcrPullThroughRule {
1360    pub ecr_repository_prefix: String,
1361    pub upstream_registry_url: String,
1362    pub upstream_registry: Option<String>,
1363    pub credential_arn: Option<String>,
1364    pub custom_role_arn: Option<String>,
1365    pub created_at: String,
1366    pub updated_at: String,
1367}
1368
1369#[derive(Debug, Clone, Serialize, Deserialize)]
1370#[serde(rename_all = "camelCase")]
1371pub struct EcrPullThroughRulesResponse {
1372    pub rules: Vec<EcrPullThroughRule>,
1373}
1374
1375#[derive(Debug, Clone, Serialize, Deserialize)]
1376#[serde(rename_all = "camelCase")]
1377pub struct EcrTag {
1378    pub key: String,
1379    pub value: String,
1380}
1381
1382#[derive(Debug, Clone, Serialize, Deserialize)]
1383#[serde(rename_all = "camelCase")]
1384pub struct EcrRepositoriesResponse {
1385    pub repositories: Vec<EcrRepository>,
1386}
1387
1388#[derive(Debug, Clone, Serialize, Deserialize)]
1389#[serde(rename_all = "camelCase")]
1390pub struct EcsCluster {
1391    pub cluster_name: String,
1392    pub cluster_arn: String,
1393    pub status: String,
1394    pub running_tasks_count: i32,
1395    pub pending_tasks_count: i32,
1396    pub active_services_count: i32,
1397    pub registered_container_instances_count: i32,
1398    pub capacity_providers: Vec<String>,
1399    pub tags: Vec<EcsTag>,
1400    pub created_at: String,
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize)]
1404#[serde(rename_all = "camelCase")]
1405pub struct EcsTag {
1406    pub key: String,
1407    pub value: String,
1408}
1409
1410#[derive(Debug, Clone, Serialize, Deserialize)]
1411#[serde(rename_all = "camelCase")]
1412pub struct EcsClustersResponse {
1413    pub clusters: Vec<EcsCluster>,
1414}
1415
1416#[derive(Debug, Clone, Serialize, Deserialize)]
1417#[serde(rename_all = "camelCase")]
1418pub struct EcsTaskContainer {
1419    pub name: String,
1420    pub image: String,
1421    pub last_status: String,
1422    pub exit_code: Option<i64>,
1423    pub runtime_id: Option<String>,
1424    pub essential: bool,
1425}
1426
1427#[derive(Debug, Clone, Serialize, Deserialize)]
1428#[serde(rename_all = "camelCase")]
1429pub struct EcsTask {
1430    pub task_arn: String,
1431    pub task_id: String,
1432    pub cluster_arn: String,
1433    pub cluster_name: String,
1434    pub task_definition_arn: String,
1435    pub family: String,
1436    pub revision: i32,
1437    pub last_status: String,
1438    pub desired_status: String,
1439    pub launch_type: String,
1440    pub created_at: String,
1441    pub started_at: Option<String>,
1442    pub stopping_at: Option<String>,
1443    pub stopped_at: Option<String>,
1444    pub stop_code: Option<String>,
1445    pub stopped_reason: Option<String>,
1446    pub group: Option<String>,
1447    pub containers: Vec<EcsTaskContainer>,
1448    pub captured_log_bytes: usize,
1449}
1450
1451#[derive(Debug, Clone, Serialize, Deserialize)]
1452#[serde(rename_all = "camelCase")]
1453pub struct EcsTasksResponse {
1454    pub tasks: Vec<EcsTask>,
1455}
1456
1457#[derive(Debug, Clone, Serialize, Deserialize)]
1458#[serde(rename_all = "camelCase")]
1459pub struct EcsTaskLogsResponse {
1460    pub task_arn: String,
1461    pub logs: String,
1462    pub last_status: String,
1463    pub exit_code: Option<i64>,
1464}
1465
1466#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1467#[serde(rename_all = "camelCase")]
1468pub struct EcsMarkFailedRequest {
1469    pub exit_code: Option<i64>,
1470    pub reason: Option<String>,
1471}
1472
1473#[derive(Debug, Clone, Serialize, Deserialize)]
1474#[serde(rename_all = "camelCase")]
1475pub struct EcsLifecycleEvent {
1476    pub at: String,
1477    pub event_type: String,
1478    pub task_arn: Option<String>,
1479    pub cluster_arn: Option<String>,
1480    pub last_status: Option<String>,
1481    pub detail: serde_json::Value,
1482}
1483
1484#[derive(Debug, Clone, Serialize, Deserialize)]
1485#[serde(rename_all = "camelCase")]
1486pub struct EcsEventsResponse {
1487    pub events: Vec<EcsLifecycleEvent>,
1488}
1489
1490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1491#[serde(rename_all = "camelCase")]
1492pub struct EcsTaskMetadataLimits {
1493    pub cpu: Option<f64>,
1494    pub memory: Option<i64>,
1495}
1496
1497#[derive(Debug, Clone, Serialize, Deserialize)]
1498#[serde(rename_all = "camelCase")]
1499pub struct EcsTaskMetadataPort {
1500    #[serde(skip_serializing_if = "Option::is_none")]
1501    pub container_port: Option<i64>,
1502    #[serde(skip_serializing_if = "Option::is_none")]
1503    pub host_port: Option<i64>,
1504    #[serde(skip_serializing_if = "Option::is_none")]
1505    pub protocol: Option<String>,
1506}
1507
1508#[derive(Debug, Clone, Serialize, Deserialize)]
1509#[serde(rename_all = "camelCase")]
1510pub struct EcsTaskMetadataContainer {
1511    pub name: String,
1512    pub image: String,
1513    #[serde(skip_serializing_if = "Option::is_none")]
1514    pub image_id: Option<String>,
1515    pub ports: Vec<EcsTaskMetadataPort>,
1516    pub labels: std::collections::BTreeMap<String, String>,
1517    pub desired_status: String,
1518    pub known_status: String,
1519    pub limits: EcsTaskMetadataLimits,
1520    #[serde(skip_serializing_if = "Option::is_none")]
1521    pub created_at: Option<String>,
1522    #[serde(skip_serializing_if = "Option::is_none")]
1523    pub started_at: Option<String>,
1524    #[serde(skip_serializing_if = "Option::is_none")]
1525    pub exit_code: Option<i64>,
1526}
1527
1528#[derive(Debug, Clone, Serialize, Deserialize)]
1529#[serde(rename_all = "camelCase")]
1530pub struct EcsTaskMetadata {
1531    pub cluster: String,
1532    pub task_arn: String,
1533    pub family: String,
1534    pub revision: i32,
1535    pub desired_status: String,
1536    pub known_status: String,
1537    pub containers: Vec<EcsTaskMetadataContainer>,
1538    #[serde(skip_serializing_if = "Option::is_none")]
1539    pub pull_started_at: Option<String>,
1540    #[serde(skip_serializing_if = "Option::is_none")]
1541    pub pull_stopped_at: Option<String>,
1542    pub availability_zone: String,
1543    pub launch_type: String,
1544    #[serde(skip_serializing_if = "Option::is_none")]
1545    pub vpc_id: Option<String>,
1546    #[serde(skip_serializing_if = "Option::is_none")]
1547    pub eni_id: Option<String>,
1548}
1549
1550#[derive(Debug, Clone, Serialize, Deserialize)]
1551#[serde(rename_all = "camelCase")]
1552pub struct EcsTaskMetadataResponse {
1553    pub task: EcsTaskMetadata,
1554}
1555
1556// ── ELBv2 ───────────────────────────────────────────────────────────
1557
1558#[derive(Debug, Clone, Serialize, Deserialize)]
1559#[serde(rename_all = "camelCase")]
1560pub struct Elbv2LoadBalancer {
1561    pub arn: String,
1562    pub name: String,
1563    pub dns_name: String,
1564    pub scheme: String,
1565    pub vpc_id: String,
1566    pub state_code: String,
1567    pub state_reason: Option<String>,
1568    pub lb_type: String,
1569    pub ip_address_type: String,
1570    pub availability_zones: Vec<Elbv2AvailabilityZone>,
1571    pub security_groups: Vec<String>,
1572    pub created_time: String,
1573    pub tags: Vec<Elbv2Tag>,
1574    /// In-process data plane TCP port for ALBs. `None` for NLB/GWLB
1575    /// or when the data plane is disabled. Tests connect to
1576    /// `127.0.0.1:<bound_port>` to reach the routed targets.
1577    #[serde(skip_serializing_if = "Option::is_none")]
1578    pub bound_port: Option<u16>,
1579}
1580
1581#[derive(Debug, Clone, Serialize, Deserialize)]
1582#[serde(rename_all = "camelCase")]
1583pub struct Elbv2AvailabilityZone {
1584    pub zone_name: String,
1585    pub subnet_id: String,
1586}
1587
1588#[derive(Debug, Clone, Serialize, Deserialize)]
1589#[serde(rename_all = "camelCase")]
1590pub struct Elbv2Tag {
1591    pub key: String,
1592    pub value: String,
1593}
1594
1595#[derive(Debug, Clone, Serialize, Deserialize)]
1596#[serde(rename_all = "camelCase")]
1597pub struct Elbv2LoadBalancersResponse {
1598    pub load_balancers: Vec<Elbv2LoadBalancer>,
1599}
1600
1601#[derive(Debug, Clone, Serialize, Deserialize)]
1602#[serde(rename_all = "camelCase")]
1603pub struct Elbv2TargetGroup {
1604    pub arn: String,
1605    pub name: String,
1606    pub protocol: Option<String>,
1607    pub port: Option<i32>,
1608    pub vpc_id: Option<String>,
1609    pub target_type: String,
1610    pub load_balancer_arns: Vec<String>,
1611    pub targets: Vec<Elbv2Target>,
1612    pub health_check_protocol: Option<String>,
1613    pub health_check_port: Option<String>,
1614    pub health_check_path: Option<String>,
1615    pub healthy_threshold_count: i32,
1616    pub unhealthy_threshold_count: i32,
1617    pub created_time: String,
1618    pub tags: Vec<Elbv2Tag>,
1619}
1620
1621#[derive(Debug, Clone, Serialize, Deserialize)]
1622#[serde(rename_all = "camelCase")]
1623pub struct Elbv2Target {
1624    pub id: String,
1625    pub port: Option<i32>,
1626    pub availability_zone: Option<String>,
1627    pub health_state: String,
1628    pub health_reason: Option<String>,
1629    pub health_description: Option<String>,
1630}
1631
1632#[derive(Debug, Clone, Serialize, Deserialize)]
1633#[serde(rename_all = "camelCase")]
1634pub struct Elbv2TargetGroupsResponse {
1635    pub target_groups: Vec<Elbv2TargetGroup>,
1636}
1637
1638#[derive(Debug, Clone, Serialize, Deserialize)]
1639#[serde(rename_all = "camelCase")]
1640pub struct Elbv2Listener {
1641    pub arn: String,
1642    pub load_balancer_arn: String,
1643    pub port: Option<i32>,
1644    pub protocol: Option<String>,
1645    pub ssl_policy: Option<String>,
1646    pub certificate_arns: Vec<String>,
1647    pub default_action_type: Option<String>,
1648    pub default_target_group_arn: Option<String>,
1649}
1650
1651#[derive(Debug, Clone, Serialize, Deserialize)]
1652#[serde(rename_all = "camelCase")]
1653pub struct Elbv2ListenersResponse {
1654    pub listeners: Vec<Elbv2Listener>,
1655}
1656
1657#[derive(Debug, Clone, Serialize, Deserialize)]
1658#[serde(rename_all = "camelCase")]
1659pub struct Elbv2Rule {
1660    pub arn: String,
1661    pub listener_arn: String,
1662    pub priority: String,
1663    pub is_default: bool,
1664    pub condition_fields: Vec<String>,
1665    pub action_type: Option<String>,
1666}
1667
1668#[derive(Debug, Clone, Serialize, Deserialize)]
1669#[serde(rename_all = "camelCase")]
1670pub struct Elbv2RulesResponse {
1671    pub rules: Vec<Elbv2Rule>,
1672}
1673
1674/// Request to bootstrap an IAM admin user in a specific account.
1675/// Used by `/_fakecloud/iam/create-admin` to solve the multi-account
1676/// bootstrap problem: there's no per-account root credential, so this
1677/// endpoint creates a user with full admin access in any account.
1678#[derive(Debug, Clone, Serialize, Deserialize)]
1679#[serde(rename_all = "camelCase")]
1680pub struct CreateAdminRequest {
1681    pub account_id: String,
1682    pub user_name: String,
1683}
1684
1685#[derive(Debug, Clone, Serialize, Deserialize)]
1686#[serde(rename_all = "camelCase")]
1687pub struct CreateAdminResponse {
1688    pub access_key_id: String,
1689    pub secret_access_key: String,
1690    pub account_id: String,
1691    pub arn: String,
1692}
1693
1694/// Body for `POST /_fakecloud/route53/health-checks/{id}/status`. The
1695/// admin endpoint flips a stored Route 53 health check's reported
1696/// status (and optionally the last-failure-reason observation) so
1697/// tests can simulate failover scenarios without a live checker.
1698#[derive(Debug, Clone, Serialize, Deserialize)]
1699#[serde(rename_all = "camelCase")]
1700pub struct Route53HealthCheckStatusRequest {
1701    /// New status reported by `GetHealthCheckStatus`. One of
1702    /// `"Success"`, `"Failure"`, `"Timeout"`, `"DnsError"`,
1703    /// `"InsufficientDataPoints"`, `"Unknown"`.
1704    pub status: Route53HealthCheckStatusValue,
1705    /// Optional last-failure observation surfaced by
1706    /// `GetHealthCheckLastFailureReason` and appended to the
1707    /// `<Status>` element for failure-flavoured statuses (`Failure`,
1708    /// `Timeout`, `DnsError`). Ignored when `status` is `Success`,
1709    /// `InsufficientDataPoints`, or `Unknown`. `None` leaves the prior
1710    /// value intact.
1711    #[serde(default)]
1712    pub reason: Option<String>,
1713}
1714
1715/// Discriminator for the admin `status` field. Mirrors the variants of
1716/// `fakecloud_route53::HealthCheckStatus` without forcing the SDK crate
1717/// to depend on the route53 crate.
1718#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1719pub enum Route53HealthCheckStatusValue {
1720    Success,
1721    Failure,
1722    Timeout,
1723    DnsError,
1724    InsufficientDataPoints,
1725    Unknown,
1726}
1727
1728/// Response body for `GET /_fakecloud/route53/zones/{id}/dnssec`. Surfaces
1729/// the deterministic ECDSA P-256 DNSSEC chain-of-trust material for a
1730/// hosted zone with at least one ACTIVE Key Signing Key. Real Route 53
1731/// keeps this material inside KMS; fakecloud derives it from the
1732/// `(zone_id, ksk_name)` pair so persistence reloads, multiple test
1733/// runs, and verifier code see stable values.
1734#[derive(Debug, Clone, Serialize, Deserialize)]
1735#[serde(rename_all = "camelCase")]
1736pub struct Route53DnssecMaterialResponse {
1737    /// Hosted zone the material belongs to (without the
1738    /// `/hostedzone/` prefix).
1739    pub hosted_zone_id: String,
1740    /// KSK name used to derive the keypair.
1741    pub key_signing_key_name: String,
1742    /// Algorithm number (always `13` for ECDSAP256SHA256).
1743    pub algorithm: u8,
1744    /// DNSKEY flags field (always `257` for a KSK).
1745    pub flags: u16,
1746    /// Standard DNSKEY key tag (RFC 4034 Appendix B).
1747    pub key_tag: u16,
1748    /// DNSKEY public-key wire bytes (`X || Y`, 64 bytes for P-256),
1749    /// base64-encoded — what would appear in the DNSKEY RDATA.
1750    pub dnskey_public_key_b64: String,
1751    /// SHA-256 DS digest hex over the canonical owner name + DNSKEY
1752    /// RDATA. Equivalent to what the parent zone publishes.
1753    pub ds_digest_sha256_hex: String,
1754}
1755
1756/// Body for `POST /_fakecloud/route53/zones/{id}/dnssec/sign`. Signs an
1757/// RRset under the zone's first ACTIVE KSK and returns the raw RRSIG
1758/// fields so tests can verify the signature against
1759/// `dnskey_public_key_b64` from `Route53DnssecMaterialResponse`.
1760#[derive(Debug, Clone, Serialize, Deserialize)]
1761#[serde(rename_all = "camelCase")]
1762pub struct Route53DnssecSignRequest {
1763    /// RRset owner name (e.g., `"www.example.com."`). Trailing dot
1764    /// optional — added if missing.
1765    pub name: String,
1766    /// Record type (`"A"`, `"AAAA"`, `"CNAME"`, `"TXT"`, ...).
1767    #[serde(rename = "type")]
1768    pub record_type: String,
1769    /// Original TTL field for the RRSIG.
1770    pub ttl: u32,
1771    /// One-or-more RDATA values matching what `ResourceRecord.Value`
1772    /// would carry on the wire.
1773    pub rdatas: Vec<String>,
1774}
1775
1776/// Response from the DNSSEC sign admin endpoint.
1777#[derive(Debug, Clone, Serialize, Deserialize)]
1778#[serde(rename_all = "camelCase")]
1779pub struct Route53DnssecSignResponse {
1780    /// Base64-encoded raw `r||s` ECDSA-P256 signature (64 bytes
1781    /// decoded).
1782    pub signature_b64: String,
1783    /// Algorithm number (always `13`).
1784    pub algorithm: u8,
1785    /// Key tag of the signing KSK.
1786    pub key_tag: u16,
1787    /// Owner name of the signer (the zone name).
1788    pub signer_name: String,
1789    /// Unix-time inception (signature validity start).
1790    pub inception: u32,
1791    /// Unix-time expiration (signature validity end).
1792    pub expiration: u32,
1793    /// Label count for the RRSIG `Labels` field.
1794    pub labels: u8,
1795    /// Original TTL echoed back from the request.
1796    pub original_ttl: u32,
1797    /// Record type echoed back from the request.
1798    #[serde(rename = "type")]
1799    pub rrset_type: String,
1800}
1801
1802/// Body for `POST /_fakecloud/acm/certificates/{arn-or-id}/status`. The
1803/// admin endpoint flips a stored ACM certificate's status (and
1804/// optionally records a failure reason) so tests can synchronously
1805/// drive a cert to `ISSUED`, `FAILED`, or `VALIDATION_TIMED_OUT`
1806/// without waiting on the auto-issue tick.
1807#[derive(Debug, Clone, Serialize, Deserialize)]
1808#[serde(rename_all = "camelCase")]
1809pub struct AcmCertificateStatusRequest {
1810    /// New certificate status. One of `"ISSUED"`, `"FAILED"`,
1811    /// `"VALIDATION_TIMED_OUT"`. Other ACM statuses are accepted as
1812    /// raw strings in case callers want to simulate a niche state.
1813    pub status: String,
1814    /// Optional failure reason surfaced as `FailureReason` in
1815    /// `DescribeCertificate`. Ignored when `status = ISSUED`. `None`
1816    /// leaves the prior value intact.
1817    #[serde(default)]
1818    pub reason: Option<String>,
1819}
1820
1821// ── Glue ────────────────────────────────────────────────────────────
1822
1823/// Curated row for `GET /_fakecloud/glue/jobs`. Mirrors the
1824/// configured Glue Job state so tests can assert what `CreateJob`
1825/// recorded without re-listing through the AWS surface.
1826#[derive(Debug, Clone, Serialize, Deserialize)]
1827#[serde(rename_all = "camelCase")]
1828pub struct GlueJob {
1829    pub account_id: String,
1830    pub name: String,
1831    pub role: String,
1832    pub command: serde_json::Value,
1833    pub default_arguments: std::collections::BTreeMap<String, String>,
1834    pub max_capacity: Option<f64>,
1835    pub max_retries: i64,
1836    pub timeout: Option<i64>,
1837    pub glue_version: Option<String>,
1838    pub worker_type: Option<String>,
1839    pub number_of_workers: Option<i64>,
1840    pub created_on: String,
1841    pub last_modified_on: String,
1842}
1843
1844/// Curated row for `GET /_fakecloud/glue/crawlers`. One entry per
1845/// crawler across every account, mirroring what `CreateCrawler`
1846/// recorded plus its lifecycle state.
1847#[derive(Debug, Clone, Serialize, Deserialize)]
1848#[serde(rename_all = "camelCase")]
1849pub struct GlueCrawler {
1850    pub account_id: String,
1851    pub name: String,
1852    pub role: String,
1853    #[serde(skip_serializing_if = "Option::is_none")]
1854    pub database_name: Option<String>,
1855    /// READY / RUNNING / STOPPING.
1856    pub state: String,
1857    /// Short summary of configured targets, e.g. "2 S3, 1 JDBC".
1858    pub target_summary: String,
1859    #[serde(skip_serializing_if = "Option::is_none")]
1860    pub schedule: Option<String>,
1861    pub creation_time: String,
1862    pub last_updated: String,
1863}
1864
1865#[derive(Debug, Clone, Serialize, Deserialize)]
1866#[serde(rename_all = "camelCase")]
1867pub struct GlueCrawlersResponse {
1868    pub crawlers: Vec<GlueCrawler>,
1869}
1870
1871// ── CloudWatch ──────────────────────────────────────────────────────
1872
1873/// A single metric dimension (name/value pair).
1874#[derive(Debug, Clone, Serialize, Deserialize)]
1875#[serde(rename_all = "camelCase")]
1876pub struct CloudWatchDimension {
1877    pub name: String,
1878    pub value: String,
1879}
1880
1881/// One alarm (metric or composite) as exposed by
1882/// `GET /_fakecloud/cloudwatch/alarms`. Metric-only fields
1883/// (`namespace`/`metricName`/`threshold`/`comparisonOperator`) are
1884/// omitted for composite alarms; `alarmRule` is present only for
1885/// composite alarms.
1886#[derive(Debug, Clone, Serialize, Deserialize)]
1887#[serde(rename_all = "camelCase")]
1888pub struct CloudWatchAlarm {
1889    pub account_id: String,
1890    pub region: String,
1891    pub name: String,
1892    /// "metric" or "composite".
1893    #[serde(rename = "type")]
1894    pub alarm_type: String,
1895    /// OK / ALARM / INSUFFICIENT_DATA.
1896    pub state: String,
1897    pub state_reason: String,
1898    #[serde(skip_serializing_if = "Option::is_none")]
1899    pub state_updated_timestamp: Option<String>,
1900    pub actions_enabled: bool,
1901    pub alarm_actions: Vec<String>,
1902    pub ok_actions: Vec<String>,
1903    pub insufficient_data_actions: Vec<String>,
1904    #[serde(skip_serializing_if = "Option::is_none")]
1905    pub namespace: Option<String>,
1906    #[serde(skip_serializing_if = "Option::is_none")]
1907    pub metric_name: Option<String>,
1908    #[serde(skip_serializing_if = "Option::is_none")]
1909    pub threshold: Option<f64>,
1910    #[serde(skip_serializing_if = "Option::is_none")]
1911    pub comparison_operator: Option<String>,
1912    #[serde(skip_serializing_if = "Option::is_none")]
1913    pub alarm_rule: Option<String>,
1914}
1915
1916#[derive(Debug, Clone, Serialize, Deserialize)]
1917#[serde(rename_all = "camelCase")]
1918pub struct CloudWatchAlarmsResponse {
1919    pub alarms: Vec<CloudWatchAlarm>,
1920}
1921
1922/// Latest datapoint summary for a metric series.
1923#[derive(Debug, Clone, Serialize, Deserialize)]
1924#[serde(rename_all = "camelCase")]
1925pub struct CloudWatchLatestDatapoint {
1926    pub timestamp: String,
1927    #[serde(skip_serializing_if = "Option::is_none")]
1928    pub value: Option<f64>,
1929    #[serde(skip_serializing_if = "Option::is_none")]
1930    pub unit: Option<String>,
1931}
1932
1933/// One unique metric series as exposed by
1934/// `GET /_fakecloud/cloudwatch/metrics`, keyed by
1935/// (account, region, namespace, metricName, dimensions).
1936#[derive(Debug, Clone, Serialize, Deserialize)]
1937#[serde(rename_all = "camelCase")]
1938pub struct CloudWatchMetric {
1939    pub account_id: String,
1940    pub region: String,
1941    pub namespace: String,
1942    pub metric_name: String,
1943    pub dimensions: Vec<CloudWatchDimension>,
1944    pub datapoint_count: usize,
1945    /// Most-recent datapoint, or `null` if the series has none.
1946    pub latest: Option<CloudWatchLatestDatapoint>,
1947}
1948
1949#[derive(Debug, Clone, Serialize, Deserialize)]
1950#[serde(rename_all = "camelCase")]
1951pub struct CloudWatchMetricsResponse {
1952    pub metrics: Vec<CloudWatchMetric>,
1953}
1954
1955// ── Firehose ────────────────────────────────────────────────────────
1956
1957/// Server-side encryption summary for a Firehose delivery stream as
1958/// exposed by `GET /_fakecloud/firehose/delivery-streams`. `status` is
1959/// `ENABLED`/`DISABLED`; `keyType`/`keyArn` are present only when a
1960/// customer-managed key is configured.
1961#[derive(Debug, Clone, Serialize, Deserialize)]
1962#[serde(rename_all = "camelCase")]
1963pub struct FirehoseEncryption {
1964    /// ENABLED / DISABLED.
1965    pub status: String,
1966    #[serde(skip_serializing_if = "Option::is_none")]
1967    pub key_type: Option<String>,
1968    #[serde(skip_serializing_if = "Option::is_none")]
1969    pub key_arn: Option<String>,
1970}
1971
1972/// One delivery stream as exposed by
1973/// `GET /_fakecloud/firehose/delivery-streams`. One entry per stream
1974/// across every account, mirroring what `CreateDeliveryStream` recorded
1975/// plus its lifecycle and encryption state.
1976#[derive(Debug, Clone, Serialize, Deserialize)]
1977#[serde(rename_all = "camelCase")]
1978pub struct FirehoseDeliveryStream {
1979    pub account_id: String,
1980    pub name: String,
1981    pub arn: String,
1982    /// DirectPut / KinesisStreamAsSource.
1983    pub stream_type: String,
1984    /// CREATING / ACTIVE / ...
1985    pub status: String,
1986    pub encryption: FirehoseEncryption,
1987    pub destination_count: usize,
1988    pub create_timestamp: String,
1989    #[serde(skip_serializing_if = "Option::is_none")]
1990    pub last_update_timestamp: Option<String>,
1991}
1992
1993#[derive(Debug, Clone, Serialize, Deserialize)]
1994#[serde(rename_all = "camelCase")]
1995pub struct FirehoseDeliveryStreamsResponse {
1996    pub delivery_streams: Vec<FirehoseDeliveryStream>,
1997}
1998
1999// ── Athena ──────────────────────────────────────────────────────────
2000
2001/// One row in the Athena named-query introspection list returned by
2002/// `GET /_fakecloud/athena/named-queries`. Mirrors the underlying named
2003/// query record plus a `last_used_at` timestamp the server bumps every
2004/// time `StartQueryExecution` resolves the query by id.
2005#[derive(Debug, Clone, Serialize, Deserialize)]
2006#[serde(rename_all = "camelCase")]
2007pub struct AthenaNamedQuery {
2008    pub named_query_id: String,
2009    pub name: String,
2010    #[serde(default)]
2011    pub description: Option<String>,
2012    pub database: String,
2013    pub query_string: String,
2014    pub workgroup: String,
2015    /// RFC3339 timestamp of the most recent `StartQueryExecution` that
2016    /// resolved its query string from this named query. `None` until the
2017    /// first such invocation.
2018    #[serde(default)]
2019    pub last_used_at: Option<String>,
2020}
2021
2022#[derive(Debug, Clone, Serialize, Deserialize)]
2023#[serde(rename_all = "camelCase")]
2024pub struct GlueJobsResponse {
2025    pub jobs: Vec<GlueJob>,
2026}
2027
2028/// Curated row for `GET /_fakecloud/glue/job-runs`. Includes the
2029/// full state machine of a JobRun (StartJobRun ledger). Filter by
2030/// `?job_name=foo` to scope to a single job.
2031#[derive(Debug, Clone, Serialize, Deserialize)]
2032#[serde(rename_all = "camelCase")]
2033pub struct GlueJobRun {
2034    pub account_id: String,
2035    pub id: String,
2036    pub job_name: String,
2037    pub attempt: i64,
2038    pub started_on: String,
2039    pub completed_on: Option<String>,
2040    pub job_run_state: String,
2041    pub arguments: std::collections::BTreeMap<String, String>,
2042    pub error_message: Option<String>,
2043    pub execution_time: i64,
2044}
2045
2046// ── Organizations ───────────────────────────────────────────────────
2047
2048/// A single member account as exposed by
2049/// `GET /_fakecloud/organizations/accounts`. Mirrors the AWS
2050/// Organizations `Account` shape but adds two fakecloud-only fields
2051/// useful for test assertions: `parentOuId` (resolved parent OU or
2052/// root) and `scpAttached` (the set of SCP IDs directly attached to
2053/// the account — does not walk up the hierarchy).
2054#[derive(Debug, Clone, Serialize, Deserialize)]
2055#[serde(rename_all = "camelCase")]
2056pub struct OrganizationsAccount {
2057    pub id: String,
2058    pub arn: String,
2059    pub email: String,
2060    pub name: String,
2061    /// AWS lifecycle state. One of `ACTIVE`, `SUSPENDED`,
2062    /// `PENDING_CLOSURE`.
2063    pub status: String,
2064    /// How the account entered the organization. One of `INVITED`,
2065    /// `CREATED`.
2066    pub joined_method: String,
2067    /// RFC3339 timestamp the account joined the org.
2068    pub joined_timestamp: String,
2069    /// Parent OU or root id. Always set for accounts attached to a
2070    /// live org; `None` only if the account record is mid-removal.
2071    #[serde(skip_serializing_if = "Option::is_none")]
2072    pub parent_ou_id: Option<String>,
2073    /// Tags directly attached to the account (alphabetical by key).
2074    #[serde(default)]
2075    pub tags: Vec<OrganizationsTag>,
2076    /// SCP ids directly attached to the account (alphabetical).
2077    /// Does not include policies inherited from parent OUs or root.
2078    #[serde(default)]
2079    pub scp_attached: Vec<String>,
2080}
2081
2082#[derive(Debug, Clone, Serialize, Deserialize)]
2083#[serde(rename_all = "camelCase")]
2084pub struct GlueJobRunsResponse {
2085    pub runs: Vec<GlueJobRun>,
2086}
2087
2088#[derive(Debug, Clone, Serialize, Deserialize)]
2089#[serde(rename_all = "camelCase")]
2090pub struct AthenaNamedQueriesResponse {
2091    pub queries: Vec<AthenaNamedQuery>,
2092}
2093
2094#[derive(Debug, Clone, Serialize, Deserialize)]
2095#[serde(rename_all = "camelCase")]
2096pub struct OrganizationsTag {
2097    pub key: String,
2098    pub value: String,
2099}
2100
2101/// Response body for `GET /_fakecloud/organizations/accounts`.
2102///
2103/// `managementAccountId` and `masterAccountId` are duplicates — AWS
2104/// renamed `Master` to `Management` in 2020 but kept the old field
2105/// around for back-compat. Both are returned here so SDKs in either
2106/// vintage match.
2107///
2108/// When no organization has been created yet, `accounts` is empty and
2109/// the account-id fields are `None`.
2110#[derive(Debug, Clone, Serialize, Deserialize)]
2111#[serde(rename_all = "camelCase")]
2112pub struct OrganizationsAccountsResponse {
2113    pub accounts: Vec<OrganizationsAccount>,
2114    #[serde(skip_serializing_if = "Option::is_none")]
2115    pub management_account_id: Option<String>,
2116    #[serde(skip_serializing_if = "Option::is_none")]
2117    pub master_account_id: Option<String>,
2118}
2119
2120/// One billing-responsibility transfer as exposed by
2121/// `GET /_fakecloud/organizations/responsibility-transfers`. Mirrors the
2122/// AWS `ResponsibilityTransfer` shape: `direction` is `INBOUND`/`OUTBOUND`,
2123/// `status` walks the transfer lifecycle, and `activeHandshakeId` points
2124/// at the handshake the invited org accepts/declines (or `null`).
2125#[derive(Debug, Clone, Serialize, Deserialize)]
2126#[serde(rename_all = "camelCase")]
2127pub struct OrganizationsResponsibilityTransfer {
2128    pub id: String,
2129    pub arn: String,
2130    pub name: String,
2131    #[serde(rename = "type")]
2132    pub transfer_type: String,
2133    pub status: String,
2134    /// INBOUND / OUTBOUND.
2135    pub direction: String,
2136    pub source_management_account_id: String,
2137    pub source_management_account_email: String,
2138    pub target_management_account_id: String,
2139    pub target_management_account_email: String,
2140    /// RFC3339 timestamp the transfer was initiated.
2141    pub start_timestamp: String,
2142    /// RFC3339 timestamp the transfer concluded, or `null` while open.
2143    #[serde(skip_serializing_if = "Option::is_none")]
2144    pub end_timestamp: Option<String>,
2145    #[serde(skip_serializing_if = "Option::is_none")]
2146    pub active_handshake_id: Option<String>,
2147}
2148
2149#[derive(Debug, Clone, Serialize, Deserialize)]
2150#[serde(rename_all = "camelCase")]
2151pub struct OrganizationsResponsibilityTransfersResponse {
2152    pub responsibility_transfers: Vec<OrganizationsResponsibilityTransfer>,
2153}
2154
2155/// Body for `POST /_fakecloud/cloudfront/distributions/{id}/status`. The
2156/// admin endpoint flips a stored CloudFront Distribution's status so
2157/// tests can synchronously force it into `Deployed` or `InProgress`
2158/// without waiting on the propagation tick.
2159#[derive(Debug, Clone, Serialize, Deserialize)]
2160#[serde(rename_all = "camelCase")]
2161pub struct CloudFrontDistributionStatusRequest {
2162    /// New distribution status. Typically `"Deployed"` or `"InProgress"`.
2163    pub status: String,
2164}
2165
2166// ── ACM (introspection) ─────────────────────────────────────────────
2167
2168/// Response body for `GET /_fakecloud/acm/certificates/{arn-or-id}/chain-info`.
2169/// Reports PEM block/byte counts and a `status` / `cert_type` snapshot
2170/// so tests can verify that uploaded chains round-trip intact. The
2171/// `external_ca_validated` flag is always `false` to document that
2172/// fakecloud does not run real X.509 verification.
2173#[derive(Debug, Clone, Serialize, Deserialize)]
2174#[serde(rename_all = "snake_case")]
2175pub struct AcmCertificateChainInfo {
2176    pub certificate_arn: String,
2177    pub certificate_pem_bytes: u64,
2178    pub certificate_pem_blocks: u64,
2179    pub chain_pem_bytes: u64,
2180    pub chain_pem_blocks: u64,
2181    pub external_ca_validated: bool,
2182    pub status: String,
2183    pub cert_type: String,
2184}
2185
2186// ── Cognito extras ──────────────────────────────────────────────────
2187
2188/// Response from `POST /_fakecloud/cognito/compromised-passwords`. Echoes
2189/// the count of *new* password hashes added to the compromised-credentials
2190/// set on this call.
2191#[derive(Debug, Clone, Serialize, Deserialize)]
2192#[serde(rename_all = "camelCase")]
2193pub struct CompromisedPasswordsResponse {
2194    pub added: u64,
2195}
2196
2197/// One registered WebAuthn credential surfaced by
2198/// `GET /_fakecloud/cognito/webauthn-credentials`. `attestation_info` is
2199/// kept as raw JSON because its shape depends on the attestation format.
2200#[derive(Debug, Clone, Serialize, Deserialize)]
2201pub struct WebAuthnCredential {
2202    pub account_id: String,
2203    pub pool_user: String,
2204    pub credential_id: String,
2205    pub relying_party_id: String,
2206    pub attestation_info: serde_json::Value,
2207}
2208
2209#[derive(Debug, Clone, Serialize, Deserialize)]
2210pub struct WebAuthnCredentialsResponse {
2211    pub credentials: Vec<WebAuthnCredential>,
2212}
2213
2214// ── SES extras (admin responses) ────────────────────────────────────
2215
2216/// Response from `POST /_fakecloud/ses/identities/{name}/mail-from-status`.
2217#[derive(Debug, Clone, Serialize, Deserialize)]
2218#[serde(rename_all = "camelCase")]
2219pub struct SesMailFromStatusResponse {
2220    pub identity: String,
2221    pub mail_from_domain_status: String,
2222}
2223
2224/// Response from `GET /_fakecloud/ses/identities/{name}/dkim-public-key`.
2225#[derive(Debug, Clone, Serialize, Deserialize)]
2226#[serde(rename_all = "camelCase")]
2227pub struct SesDkimPublicKeyResponse {
2228    pub identity: String,
2229    pub selector: String,
2230    pub public_key_base64: String,
2231    pub signing_enabled: bool,
2232}
2233
2234/// Response from `POST /_fakecloud/ses/account/sandbox`.
2235#[derive(Debug, Clone, Serialize, Deserialize)]
2236#[serde(rename_all = "camelCase")]
2237pub struct SesSandboxResponse {
2238    pub sandbox: bool,
2239    pub production_access_enabled: bool,
2240}
2241
2242/// Response from `GET /_fakecloud/ses/metrics`. fakecloud surfaces a
2243/// running `suppressedDropsTotal` counter so test code can verify that
2244/// the suppression list short-circuits sends.
2245#[derive(Debug, Clone, Serialize, Deserialize)]
2246#[serde(rename_all = "camelCase")]
2247pub struct SesMetricsResponse {
2248    pub suppressed_drops_total: u64,
2249}
2250
2251// ── ELBv2 admin ─────────────────────────────────────────────────────
2252
2253/// Response from `POST /_fakecloud/elbv2/access-logs/flush`. `flushed`
2254/// is the number of access-log records flushed to the configured S3
2255/// bucket on this call.
2256#[derive(Debug, Clone, Serialize, Deserialize)]
2257#[serde(rename_all = "camelCase")]
2258pub struct Elbv2AccessLogsFlushResponse {
2259    pub flushed: u64,
2260}
2261
2262// ── API Gateway v2 WebSocket connections ────────────────────────────
2263
2264/// Single active WebSocket connection tracked by the API Gateway v2
2265/// fake. Returned by `GET /_fakecloud/apigatewayv2/connections`.
2266#[derive(Debug, Clone, Serialize, Deserialize)]
2267#[serde(rename_all = "camelCase")]
2268pub struct ApiGatewayV2Connection {
2269    pub connection_id: String,
2270    pub api_id: String,
2271    pub stage: String,
2272    pub connected_at: String,
2273    pub last_active_at: String,
2274    pub source_ip: String,
2275}
2276
2277#[derive(Debug, Clone, Serialize, Deserialize)]
2278#[serde(rename_all = "camelCase")]
2279pub struct ApiGatewayV2ConnectionsResponse {
2280    pub connections: Vec<ApiGatewayV2Connection>,
2281}
2282
2283// ── ECS task IAM credentials ────────────────────────────────────────
2284
2285/// Response shape for `GET /_fakecloud/ecs/creds/{task_id}`. Matches the
2286/// real ECS task metadata credential endpoint field casing (PascalCase),
2287/// so this type is `Deserialize` only — fakecloud writes the keys
2288/// already capitalized.
2289#[derive(Debug, Clone, Serialize, Deserialize)]
2290pub struct EcsTaskCredentialsResponse {
2291    #[serde(rename = "AccessKeyId")]
2292    pub access_key_id: String,
2293    #[serde(rename = "SecretAccessKey")]
2294    pub secret_access_key: String,
2295    #[serde(rename = "Token")]
2296    pub token: String,
2297    #[serde(rename = "Expiration")]
2298    pub expiration: String,
2299    #[serde(rename = "RoleArn")]
2300    pub role_arn: String,
2301}
2302
2303// ── KMS usage (admin) ───────────────────────────────────────────────
2304
2305/// One recorded KMS data-plane invocation, exposed by
2306/// `GET /_fakecloud/kms/usage`. Fields mirror the JSON payload emitted
2307/// by the server's usage recorder.
2308#[derive(Debug, Clone, Serialize, Deserialize)]
2309#[serde(rename_all = "camelCase")]
2310pub struct KmsUsageRecord {
2311    pub timestamp: String,
2312    pub operation: String,
2313    pub service_principal: Option<String>,
2314    pub account_id: String,
2315    pub key_arn: String,
2316    pub encryption_context: Option<serde_json::Value>,
2317}
2318
2319#[derive(Debug, Clone, Serialize, Deserialize)]
2320#[serde(rename_all = "camelCase")]
2321pub struct KmsUsageResponse {
2322    pub records: Vec<KmsUsageRecord>,
2323}
2324
2325// ── ELBv2 WAF counts (admin) ────────────────────────────────────────
2326
2327/// Response body for `GET /_fakecloud/elbv2/waf-counts`. The exact
2328/// shape of `counts` is service-internal and intentionally left as
2329/// free-form JSON so we don't have to track every new dimension in
2330/// the SDK.
2331#[derive(Debug, Clone, Serialize, Deserialize)]
2332#[serde(rename_all = "camelCase")]
2333pub struct Elbv2WafCountsResponse {
2334    pub counts: serde_json::Value,
2335}
2336
2337// ── EC2 instances (introspection) ───────────────────────────────────
2338
2339/// A single EC2 instance as surfaced by `GET /_fakecloud/ec2/instances`.
2340/// Instances are metadata-faithful today (Docker-backed execution is a
2341/// roadmap follow-up), so this mirrors the control-plane view without
2342/// leaking runtime-internal fields.
2343#[derive(Debug, Clone, Serialize, Deserialize)]
2344#[serde(rename_all = "camelCase")]
2345pub struct Ec2Instance {
2346    pub instance_id: String,
2347    pub image_id: String,
2348    pub instance_type: String,
2349    /// EC2 state name: `pending` | `running` | `shutting-down` |
2350    /// `terminated` | `stopping` | `stopped`.
2351    pub state: String,
2352    pub private_ip: String,
2353    pub public_ip: Option<String>,
2354    pub subnet_id: Option<String>,
2355    pub vpc_id: Option<String>,
2356    pub key_name: Option<String>,
2357    pub security_group_ids: Vec<String>,
2358    pub availability_zone: String,
2359    pub launch_time: String,
2360}
2361
2362/// Response body for `GET /_fakecloud/ec2/instances`.
2363#[derive(Debug, Clone, Serialize, Deserialize)]
2364#[serde(rename_all = "camelCase")]
2365pub struct Ec2InstancesResponse {
2366    pub instances: Vec<Ec2Instance>,
2367}