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#[derive(Debug, Clone, Default, Serialize, Deserialize)]
790#[serde(rename_all = "camelCase")]
791pub struct DynamoDbSnapshotSaveRequest {
792    pub data_path: Option<String>,
793}
794
795#[derive(Debug, Clone, Serialize, Deserialize)]
796#[serde(rename_all = "camelCase")]
797pub struct DynamoDbSnapshotSaveResponse {
798    pub saved: bool,
799}
800
801// ── SecretsManager ──────────────────────────────────────────────────
802
803#[derive(Debug, Clone, Serialize, Deserialize)]
804#[serde(rename_all = "camelCase")]
805pub struct RotationTickResponse {
806    pub rotated_secrets: Vec<String>,
807}
808
809// ── ElastiCache ─────────────────────────────────────────────────────
810
811#[derive(Debug, Clone, Serialize, Deserialize)]
812#[serde(rename_all = "camelCase")]
813pub struct ElastiCacheCluster {
814    pub cache_cluster_id: String,
815    pub cache_cluster_status: String,
816    pub engine: String,
817    pub engine_version: String,
818    pub cache_node_type: String,
819    pub num_cache_nodes: i32,
820    pub replication_group_id: Option<String>,
821    pub port: Option<i32>,
822    pub host_port: Option<u16>,
823    pub container_id: Option<String>,
824}
825
826#[derive(Debug, Clone, Serialize, Deserialize)]
827#[serde(rename_all = "camelCase")]
828pub struct ElastiCacheClustersResponse {
829    pub clusters: Vec<ElastiCacheCluster>,
830}
831
832#[derive(Debug, Clone, Serialize, Deserialize)]
833#[serde(rename_all = "camelCase")]
834pub struct ElastiCacheReplicationGroupIntrospection {
835    pub replication_group_id: String,
836    pub status: String,
837    pub description: String,
838    pub member_clusters: Vec<String>,
839    pub automatic_failover: bool,
840    pub multi_az: bool,
841    pub engine: String,
842    pub engine_version: String,
843    pub cache_node_type: String,
844    pub num_cache_clusters: i32,
845}
846
847#[derive(Debug, Clone, Serialize, Deserialize)]
848#[serde(rename_all = "camelCase")]
849pub struct ElastiCacheReplicationGroupsResponse {
850    pub replication_groups: Vec<ElastiCacheReplicationGroupIntrospection>,
851}
852
853#[derive(Debug, Clone, Serialize, Deserialize)]
854#[serde(rename_all = "camelCase")]
855pub struct ElastiCacheServerlessCacheIntrospection {
856    pub serverless_cache_name: String,
857    pub status: String,
858    pub engine: String,
859    pub engine_version: String,
860    pub cache_node_type: Option<String>,
861}
862
863#[derive(Debug, Clone, Serialize, Deserialize)]
864#[serde(rename_all = "camelCase")]
865pub struct ElastiCacheServerlessCachesResponse {
866    pub serverless_caches: Vec<ElastiCacheServerlessCacheIntrospection>,
867}
868
869#[derive(Debug, Clone, Serialize, Deserialize)]
870#[serde(rename_all = "camelCase")]
871pub struct ElastiCacheAclUser {
872    pub name: String,
873    pub status: String,
874    pub access_string: String,
875    pub no_password_required: bool,
876    pub password_count: i32,
877}
878
879#[derive(Debug, Clone, Serialize, Deserialize)]
880#[serde(rename_all = "camelCase")]
881pub struct ElastiCacheAclGroup {
882    pub name: String,
883    pub members: Vec<String>,
884}
885
886#[derive(Debug, Clone, Serialize, Deserialize)]
887#[serde(rename_all = "camelCase")]
888pub struct ElastiCacheAclCluster {
889    pub cluster_id: String,
890    pub engine: String,
891    pub users: Vec<ElastiCacheAclUser>,
892    pub groups: Vec<ElastiCacheAclGroup>,
893}
894
895#[derive(Debug, Clone, Serialize, Deserialize)]
896#[serde(rename_all = "camelCase")]
897pub struct ElastiCacheAclsResponse {
898    pub acls: Vec<ElastiCacheAclCluster>,
899}
900
901// ── Step Functions ──────────────────────────────────────────────────
902
903#[derive(Debug, Clone, Serialize, Deserialize)]
904#[serde(rename_all = "camelCase")]
905pub struct StepFunctionsExecution {
906    pub execution_arn: String,
907    pub state_machine_arn: String,
908    pub name: String,
909    pub status: String,
910    #[serde(skip_serializing_if = "Option::is_none")]
911    pub input: Option<String>,
912    #[serde(skip_serializing_if = "Option::is_none")]
913    pub output: Option<String>,
914    pub start_date: String,
915    #[serde(skip_serializing_if = "Option::is_none")]
916    pub stop_date: Option<String>,
917}
918
919#[derive(Debug, Clone, Serialize, Deserialize)]
920#[serde(rename_all = "camelCase")]
921pub struct StepFunctionsExecutionsResponse {
922    pub executions: Vec<StepFunctionsExecution>,
923}
924
925#[derive(Debug, Clone, Serialize, Deserialize)]
926#[serde(rename_all = "camelCase")]
927pub struct StepFunctionsSyncBillingDetails {
928    pub billed_duration_in_milliseconds: i64,
929    pub billed_memory_used_in_mb: i64,
930}
931
932#[derive(Debug, Clone, Serialize, Deserialize)]
933#[serde(rename_all = "camelCase")]
934pub struct StepFunctionsSyncExecution {
935    pub execution_arn: String,
936    pub state_machine_arn: String,
937    pub name: String,
938    pub status: String,
939    #[serde(skip_serializing_if = "Option::is_none")]
940    pub input: Option<String>,
941    #[serde(skip_serializing_if = "Option::is_none")]
942    pub output: Option<String>,
943    pub started_at: String,
944    #[serde(skip_serializing_if = "Option::is_none")]
945    pub stopped_at: Option<String>,
946    pub duration_ms: i64,
947    pub billing_details: StepFunctionsSyncBillingDetails,
948}
949
950#[derive(Debug, Clone, Serialize, Deserialize)]
951#[serde(rename_all = "camelCase")]
952pub struct StepFunctionsSyncExecutionsResponse {
953    pub executions: Vec<StepFunctionsSyncExecution>,
954}
955
956#[derive(Debug, Clone, Serialize, Deserialize)]
957#[serde(rename_all = "camelCase")]
958pub struct StepFunctionsExecutionTreeNode {
959    pub arn: String,
960    pub state_machine_arn: String,
961    pub status: String,
962    pub started_at: String,
963    #[serde(skip_serializing_if = "Option::is_none")]
964    pub stopped_at: Option<String>,
965    pub children: Vec<StepFunctionsExecutionTreeNode>,
966}
967
968#[derive(Debug, Clone, Serialize, Deserialize)]
969#[serde(rename_all = "camelCase")]
970pub struct StepFunctionsExecutionTreeResponse {
971    pub root_arn: String,
972    pub tree: StepFunctionsExecutionTreeNode,
973}
974
975#[derive(Debug, Clone, Serialize, Deserialize, Default)]
976#[serde(rename_all = "camelCase")]
977pub struct SfnEnqueueActivityTaskRequest {
978    pub activity_arn: String,
979    #[serde(skip_serializing_if = "Option::is_none")]
980    pub input: Option<String>,
981    #[serde(skip_serializing_if = "Option::is_none")]
982    pub heartbeat_seconds: Option<i64>,
983    #[serde(skip_serializing_if = "Option::is_none")]
984    pub timeout_seconds: Option<i64>,
985}
986
987#[derive(Debug, Clone, Serialize, Deserialize)]
988#[serde(rename_all = "camelCase")]
989pub struct SfnEnqueueActivityTaskResponse {
990    pub task_token: String,
991}
992
993// ── Cognito ─────────────────────────────────────────────────────────
994
995#[derive(Debug, Clone, Serialize, Deserialize)]
996#[serde(rename_all = "camelCase")]
997pub struct UserConfirmationCodes {
998    pub confirmation_code: Option<String>,
999    pub attribute_verification_codes: serde_json::Value,
1000}
1001
1002#[derive(Debug, Clone, Serialize, Deserialize)]
1003#[serde(rename_all = "camelCase")]
1004pub struct ConfirmationCode {
1005    pub pool_id: String,
1006    pub username: String,
1007    pub code: String,
1008    #[serde(rename = "type")]
1009    pub code_type: String,
1010    #[serde(skip_serializing_if = "Option::is_none")]
1011    pub attribute: Option<String>,
1012}
1013
1014#[derive(Debug, Clone, Serialize, Deserialize)]
1015#[serde(rename_all = "camelCase")]
1016pub struct ConfirmationCodesResponse {
1017    pub codes: Vec<ConfirmationCode>,
1018}
1019
1020#[derive(Debug, Clone, Serialize, Deserialize)]
1021#[serde(rename_all = "camelCase")]
1022pub struct ConfirmUserRequest {
1023    pub user_pool_id: String,
1024    pub username: String,
1025}
1026
1027#[derive(Debug, Clone, Serialize, Deserialize)]
1028#[serde(rename_all = "camelCase")]
1029pub struct ConfirmUserResponse {
1030    pub confirmed: bool,
1031    #[serde(skip_serializing_if = "Option::is_none")]
1032    pub error: Option<String>,
1033}
1034
1035#[derive(Debug, Clone, Serialize, Deserialize)]
1036#[serde(rename_all = "camelCase")]
1037pub struct TokenInfo {
1038    #[serde(rename = "type")]
1039    pub token_type: String,
1040    pub username: String,
1041    pub pool_id: String,
1042    pub client_id: String,
1043    pub issued_at: f64,
1044}
1045
1046#[derive(Debug, Clone, Serialize, Deserialize)]
1047#[serde(rename_all = "camelCase")]
1048pub struct TokensResponse {
1049    pub tokens: Vec<TokenInfo>,
1050}
1051
1052#[derive(Debug, Clone, Serialize, Deserialize)]
1053#[serde(rename_all = "camelCase")]
1054pub struct ExpireTokensRequest {
1055    #[serde(skip_serializing_if = "Option::is_none")]
1056    pub user_pool_id: Option<String>,
1057    #[serde(skip_serializing_if = "Option::is_none")]
1058    pub username: Option<String>,
1059}
1060
1061#[derive(Debug, Clone, Serialize, Deserialize)]
1062#[serde(rename_all = "camelCase")]
1063pub struct ExpireTokensResponse {
1064    pub expired_tokens: u64,
1065}
1066
1067#[derive(Debug, Clone, Serialize, Deserialize)]
1068#[serde(rename_all = "camelCase")]
1069pub struct AuthEvent {
1070    pub event_type: String,
1071    pub username: String,
1072    pub user_pool_id: String,
1073    pub client_id: Option<String>,
1074    pub timestamp: f64,
1075    pub success: bool,
1076}
1077
1078#[derive(Debug, Clone, Serialize, Deserialize)]
1079#[serde(rename_all = "camelCase")]
1080pub struct AuthEventsResponse {
1081    pub events: Vec<AuthEvent>,
1082}
1083
1084/// One PreTokenGeneration Lambda trigger invocation captured for
1085/// introspection at `/_fakecloud/cognito/pretokengen/invocations`.
1086/// `claims_added` / `claims_overridden` / `group_overrides` are
1087/// pre-parsed from the Lambda response so test callers don't have to
1088/// walk the raw `claimsAndScopeOverrideDetails` shape themselves.
1089#[derive(Debug, Clone, Serialize, Deserialize)]
1090#[serde(rename_all = "camelCase")]
1091pub struct PreTokenGenInvocation {
1092    pub pool_id: String,
1093    pub user_pool_arn: String,
1094    pub username: String,
1095    pub trigger_source: String,
1096    pub lambda_arn: String,
1097    pub request_payload: serde_json::Value,
1098    pub response_payload: Option<serde_json::Value>,
1099    pub claims_added: Vec<String>,
1100    pub claims_overridden: Vec<String>,
1101    pub group_overrides: Vec<String>,
1102    /// RFC3339 timestamp.
1103    pub invoked_at: String,
1104    pub duration_ms: u64,
1105}
1106
1107#[derive(Debug, Clone, Serialize, Deserialize)]
1108#[serde(rename_all = "camelCase")]
1109pub struct PreTokenGenInvocationsResponse {
1110    pub invocations: Vec<PreTokenGenInvocation>,
1111}
1112
1113/// Request body for the `/_fakecloud/cognito/authorization-codes` admin
1114/// mint endpoint. Lets test harnesses (and any caller that wants to
1115/// drive the `authorization_code` grant before the Y4 hosted-UI lands)
1116/// pre-allocate the same `(client_id, redirect_uri, scopes, PKCE)`
1117/// binding the real `/oauth2/authorize` endpoint will eventually
1118/// produce.
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1120#[serde(rename_all = "camelCase")]
1121pub struct MintAuthorizationCodeRequest {
1122    pub user_pool_id: String,
1123    pub client_id: String,
1124    pub username: String,
1125    pub redirect_uri: String,
1126    #[serde(default)]
1127    pub scopes: Vec<String>,
1128    #[serde(skip_serializing_if = "Option::is_none")]
1129    pub code_challenge: Option<String>,
1130    #[serde(skip_serializing_if = "Option::is_none")]
1131    pub code_challenge_method: Option<String>,
1132    #[serde(skip_serializing_if = "Option::is_none")]
1133    pub nonce: Option<String>,
1134}
1135
1136#[derive(Debug, Clone, Serialize, Deserialize)]
1137#[serde(rename_all = "camelCase")]
1138pub struct MintAuthorizationCodeResponse {
1139    pub code: String,
1140}
1141
1142// ── API Gateway v2 ──────────────────────────────────────────────────
1143
1144#[derive(Debug, Clone, Serialize, Deserialize)]
1145#[serde(rename_all = "camelCase")]
1146pub struct ApiGatewayV2Request {
1147    pub request_id: String,
1148    pub api_id: String,
1149    pub stage: String,
1150    pub method: String,
1151    pub path: String,
1152    pub headers: std::collections::HashMap<String, String>,
1153    pub query_params: std::collections::HashMap<String, String>,
1154    #[serde(skip_serializing_if = "Option::is_none")]
1155    pub body: Option<String>,
1156    pub timestamp: String,
1157    pub status_code: u16,
1158}
1159
1160#[derive(Debug, Clone, Serialize, Deserialize)]
1161#[serde(rename_all = "camelCase")]
1162pub struct ApiGatewayV2RequestsResponse {
1163    pub requests: Vec<ApiGatewayV2Request>,
1164}
1165
1166// ── Bedrock ────────────────────────────────────────────────────────
1167
1168#[derive(Debug, Clone, Serialize, Deserialize)]
1169#[serde(rename_all = "camelCase")]
1170pub struct BedrockInvocation {
1171    pub model_id: String,
1172    pub input: String,
1173    pub output: String,
1174    pub timestamp: String,
1175    /// Error detail for faulted calls, or `None` on success.
1176    #[serde(default)]
1177    pub error: Option<String>,
1178}
1179
1180#[derive(Debug, Clone, Serialize, Deserialize)]
1181#[serde(rename_all = "camelCase")]
1182pub struct BedrockInvocationsResponse {
1183    pub invocations: Vec<BedrockInvocation>,
1184}
1185
1186#[derive(Debug, Clone, Serialize, Deserialize)]
1187#[serde(rename_all = "camelCase")]
1188pub struct BedrockModelResponseConfig {
1189    pub status: String,
1190    pub model_id: String,
1191}
1192
1193/// One rule in a per-model response rule list.
1194///
1195/// `prompt_contains` is a substring that must appear in the prompt for this
1196/// rule to match. `None` or an empty string matches any prompt.
1197#[derive(Debug, Clone, Serialize, Deserialize)]
1198#[serde(rename_all = "camelCase")]
1199pub struct BedrockResponseRule {
1200    #[serde(default, skip_serializing_if = "Option::is_none")]
1201    pub prompt_contains: Option<String>,
1202    pub response: String,
1203}
1204
1205/// Configuration for a fault to inject on Bedrock runtime calls.
1206#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1207#[serde(rename_all = "camelCase")]
1208pub struct BedrockFaultRule {
1209    pub error_type: String,
1210    #[serde(default, skip_serializing_if = "Option::is_none")]
1211    pub message: Option<String>,
1212    #[serde(default, skip_serializing_if = "Option::is_none")]
1213    pub http_status: Option<u16>,
1214    #[serde(default, skip_serializing_if = "Option::is_none")]
1215    pub count: Option<u32>,
1216    #[serde(default, skip_serializing_if = "Option::is_none")]
1217    pub model_id: Option<String>,
1218    #[serde(default, skip_serializing_if = "Option::is_none")]
1219    pub operation: Option<String>,
1220}
1221
1222/// Server-side view of a queued fault rule.
1223#[derive(Debug, Clone, Serialize, Deserialize)]
1224#[serde(rename_all = "camelCase")]
1225pub struct BedrockFaultRuleState {
1226    pub error_type: String,
1227    pub message: String,
1228    pub http_status: u16,
1229    pub remaining: u32,
1230    #[serde(default)]
1231    pub model_id: Option<String>,
1232    #[serde(default)]
1233    pub operation: Option<String>,
1234}
1235
1236#[derive(Debug, Clone, Serialize, Deserialize)]
1237#[serde(rename_all = "camelCase")]
1238pub struct BedrockFaultsResponse {
1239    pub faults: Vec<BedrockFaultRuleState>,
1240}
1241
1242#[derive(Debug, Clone, Serialize, Deserialize)]
1243#[serde(rename_all = "camelCase")]
1244pub struct BedrockStatusResponse {
1245    pub status: String,
1246}
1247
1248#[derive(Debug, Clone, Serialize, Deserialize)]
1249#[serde(rename_all = "camelCase")]
1250pub struct BedrockAgentAliasSummary {
1251    pub alias_id: String,
1252    pub alias_name: String,
1253    pub agent_version: String,
1254    pub alias_arn: String,
1255    pub status: String,
1256    pub created_at: String,
1257    pub updated_at: String,
1258}
1259
1260#[derive(Debug, Clone, Serialize, Deserialize)]
1261#[serde(rename_all = "camelCase")]
1262pub struct BedrockAgentVersionSummary {
1263    pub agent_version: String,
1264    pub created_at: String,
1265    pub instruction: Option<String>,
1266    pub foundation_model: Option<String>,
1267}
1268
1269#[derive(Debug, Clone, Serialize, Deserialize)]
1270#[serde(rename_all = "camelCase")]
1271pub struct BedrockAgentKnowledgeBaseSummary {
1272    pub knowledge_base_id: String,
1273    pub state: String,
1274    pub description: Option<String>,
1275}
1276
1277#[derive(Debug, Clone, Serialize, Deserialize)]
1278#[serde(rename_all = "camelCase")]
1279pub struct BedrockAgentCollaboratorSummary {
1280    pub collaborator_id: String,
1281    pub collaborator_name: String,
1282    pub collaborator_alias_arn: String,
1283    pub relay_conversation_history: String,
1284}
1285
1286#[derive(Debug, Clone, Serialize, Deserialize)]
1287#[serde(rename_all = "camelCase")]
1288pub struct BedrockAgentRow {
1289    pub agent_id: String,
1290    pub agent_name: String,
1291    pub agent_arn: String,
1292    pub agent_status: String,
1293    pub foundation_model: Option<String>,
1294    pub instruction: Option<String>,
1295    pub knowledge_bases: Vec<BedrockAgentKnowledgeBaseSummary>,
1296    pub action_groups: Vec<serde_json::Value>,
1297    pub collaborators: Vec<BedrockAgentCollaboratorSummary>,
1298    pub aliases: Vec<BedrockAgentAliasSummary>,
1299    pub versions: Vec<BedrockAgentVersionSummary>,
1300    pub prompt_overrides: Option<serde_json::Value>,
1301    pub created_at: String,
1302    pub updated_at: String,
1303}
1304
1305#[derive(Debug, Clone, Serialize, Deserialize)]
1306#[serde(rename_all = "camelCase")]
1307pub struct BedrockAgentAgentsResponse {
1308    pub agents: Vec<BedrockAgentRow>,
1309}
1310
1311#[derive(Debug, Clone, Serialize, Deserialize)]
1312#[serde(rename_all = "camelCase")]
1313pub struct BedrockAgentRuntimeInvocation {
1314    pub invocation_id: String,
1315    pub op: String,
1316    pub agent_id: Option<String>,
1317    pub flow_id: Option<String>,
1318    pub session_id: Option<String>,
1319    pub input: String,
1320    pub output: String,
1321    pub output_chunks: u32,
1322    pub trace: Option<serde_json::Value>,
1323    #[serde(default)]
1324    pub citations: Vec<serde_json::Value>,
1325    pub invoked_at: String,
1326    pub duration_ms: u64,
1327}
1328
1329#[derive(Debug, Clone, Serialize, Deserialize)]
1330#[serde(rename_all = "camelCase")]
1331pub struct BedrockAgentRuntimeInvocationsResponse {
1332    pub invocations: Vec<BedrockAgentRuntimeInvocation>,
1333}
1334
1335#[derive(Debug, Clone, Serialize, Deserialize)]
1336#[serde(rename_all = "camelCase")]
1337pub struct EcrRepository {
1338    pub repository_name: String,
1339    pub repository_arn: String,
1340    pub registry_id: String,
1341    pub repository_uri: String,
1342    pub image_tag_mutability: String,
1343    pub scan_on_push: bool,
1344    pub created_at: String,
1345    pub tags: Vec<EcrTag>,
1346    pub has_policy: bool,
1347    pub has_lifecycle_policy: bool,
1348    pub image_count: u64,
1349    pub layer_count: u64,
1350}
1351
1352#[derive(Debug, Clone, Serialize, Deserialize)]
1353#[serde(rename_all = "camelCase")]
1354pub struct EcrImage {
1355    pub repository_name: String,
1356    pub image_digest: String,
1357    pub image_tags: Vec<String>,
1358    pub image_size_in_bytes: u64,
1359    pub image_manifest_media_type: String,
1360    pub image_pushed_at: String,
1361}
1362
1363#[derive(Debug, Clone, Serialize, Deserialize)]
1364#[serde(rename_all = "camelCase")]
1365pub struct EcrImagesResponse {
1366    pub images: Vec<EcrImage>,
1367}
1368
1369#[derive(Debug, Clone, Serialize, Deserialize)]
1370#[serde(rename_all = "camelCase")]
1371pub struct EcrPullThroughRule {
1372    pub ecr_repository_prefix: String,
1373    pub upstream_registry_url: String,
1374    pub upstream_registry: Option<String>,
1375    pub credential_arn: Option<String>,
1376    pub custom_role_arn: Option<String>,
1377    pub created_at: String,
1378    pub updated_at: String,
1379}
1380
1381#[derive(Debug, Clone, Serialize, Deserialize)]
1382#[serde(rename_all = "camelCase")]
1383pub struct EcrPullThroughRulesResponse {
1384    pub rules: Vec<EcrPullThroughRule>,
1385}
1386
1387#[derive(Debug, Clone, Serialize, Deserialize)]
1388#[serde(rename_all = "camelCase")]
1389pub struct EcrTag {
1390    pub key: String,
1391    pub value: String,
1392}
1393
1394#[derive(Debug, Clone, Serialize, Deserialize)]
1395#[serde(rename_all = "camelCase")]
1396pub struct EcrRepositoriesResponse {
1397    pub repositories: Vec<EcrRepository>,
1398}
1399
1400#[derive(Debug, Clone, Serialize, Deserialize)]
1401#[serde(rename_all = "camelCase")]
1402pub struct EcsCluster {
1403    pub cluster_name: String,
1404    pub cluster_arn: String,
1405    pub status: String,
1406    pub running_tasks_count: i32,
1407    pub pending_tasks_count: i32,
1408    pub active_services_count: i32,
1409    pub registered_container_instances_count: i32,
1410    pub capacity_providers: Vec<String>,
1411    pub tags: Vec<EcsTag>,
1412    pub created_at: String,
1413}
1414
1415#[derive(Debug, Clone, Serialize, Deserialize)]
1416#[serde(rename_all = "camelCase")]
1417pub struct EcsTag {
1418    pub key: String,
1419    pub value: String,
1420}
1421
1422#[derive(Debug, Clone, Serialize, Deserialize)]
1423#[serde(rename_all = "camelCase")]
1424pub struct EcsClustersResponse {
1425    pub clusters: Vec<EcsCluster>,
1426}
1427
1428#[derive(Debug, Clone, Serialize, Deserialize)]
1429#[serde(rename_all = "camelCase")]
1430pub struct EcsTaskContainer {
1431    pub name: String,
1432    pub image: String,
1433    pub last_status: String,
1434    pub exit_code: Option<i64>,
1435    pub runtime_id: Option<String>,
1436    pub essential: bool,
1437}
1438
1439#[derive(Debug, Clone, Serialize, Deserialize)]
1440#[serde(rename_all = "camelCase")]
1441pub struct EcsTask {
1442    pub task_arn: String,
1443    pub task_id: String,
1444    pub cluster_arn: String,
1445    pub cluster_name: String,
1446    pub task_definition_arn: String,
1447    pub family: String,
1448    pub revision: i32,
1449    pub last_status: String,
1450    pub desired_status: String,
1451    pub launch_type: String,
1452    pub created_at: String,
1453    pub started_at: Option<String>,
1454    pub stopping_at: Option<String>,
1455    pub stopped_at: Option<String>,
1456    pub stop_code: Option<String>,
1457    pub stopped_reason: Option<String>,
1458    pub group: Option<String>,
1459    pub containers: Vec<EcsTaskContainer>,
1460    pub captured_log_bytes: usize,
1461}
1462
1463#[derive(Debug, Clone, Serialize, Deserialize)]
1464#[serde(rename_all = "camelCase")]
1465pub struct EcsTasksResponse {
1466    pub tasks: Vec<EcsTask>,
1467}
1468
1469#[derive(Debug, Clone, Serialize, Deserialize)]
1470#[serde(rename_all = "camelCase")]
1471pub struct EcsTaskLogsResponse {
1472    pub task_arn: String,
1473    pub logs: String,
1474    pub last_status: String,
1475    pub exit_code: Option<i64>,
1476}
1477
1478#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1479#[serde(rename_all = "camelCase")]
1480pub struct EcsMarkFailedRequest {
1481    pub exit_code: Option<i64>,
1482    pub reason: Option<String>,
1483}
1484
1485#[derive(Debug, Clone, Serialize, Deserialize)]
1486#[serde(rename_all = "camelCase")]
1487pub struct EcsLifecycleEvent {
1488    pub at: String,
1489    pub event_type: String,
1490    pub task_arn: Option<String>,
1491    pub cluster_arn: Option<String>,
1492    pub last_status: Option<String>,
1493    pub detail: serde_json::Value,
1494}
1495
1496#[derive(Debug, Clone, Serialize, Deserialize)]
1497#[serde(rename_all = "camelCase")]
1498pub struct EcsEventsResponse {
1499    pub events: Vec<EcsLifecycleEvent>,
1500}
1501
1502#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1503#[serde(rename_all = "camelCase")]
1504pub struct EcsTaskMetadataLimits {
1505    pub cpu: Option<f64>,
1506    pub memory: Option<i64>,
1507}
1508
1509#[derive(Debug, Clone, Serialize, Deserialize)]
1510#[serde(rename_all = "camelCase")]
1511pub struct EcsTaskMetadataPort {
1512    #[serde(skip_serializing_if = "Option::is_none")]
1513    pub container_port: Option<i64>,
1514    #[serde(skip_serializing_if = "Option::is_none")]
1515    pub host_port: Option<i64>,
1516    #[serde(skip_serializing_if = "Option::is_none")]
1517    pub protocol: Option<String>,
1518}
1519
1520#[derive(Debug, Clone, Serialize, Deserialize)]
1521#[serde(rename_all = "camelCase")]
1522pub struct EcsTaskMetadataContainer {
1523    pub name: String,
1524    pub image: String,
1525    #[serde(skip_serializing_if = "Option::is_none")]
1526    pub image_id: Option<String>,
1527    pub ports: Vec<EcsTaskMetadataPort>,
1528    pub labels: std::collections::BTreeMap<String, String>,
1529    pub desired_status: String,
1530    pub known_status: String,
1531    pub limits: EcsTaskMetadataLimits,
1532    #[serde(skip_serializing_if = "Option::is_none")]
1533    pub created_at: Option<String>,
1534    #[serde(skip_serializing_if = "Option::is_none")]
1535    pub started_at: Option<String>,
1536    #[serde(skip_serializing_if = "Option::is_none")]
1537    pub exit_code: Option<i64>,
1538}
1539
1540#[derive(Debug, Clone, Serialize, Deserialize)]
1541#[serde(rename_all = "camelCase")]
1542pub struct EcsTaskMetadata {
1543    pub cluster: String,
1544    pub task_arn: String,
1545    pub family: String,
1546    pub revision: i32,
1547    pub desired_status: String,
1548    pub known_status: String,
1549    pub containers: Vec<EcsTaskMetadataContainer>,
1550    #[serde(skip_serializing_if = "Option::is_none")]
1551    pub pull_started_at: Option<String>,
1552    #[serde(skip_serializing_if = "Option::is_none")]
1553    pub pull_stopped_at: Option<String>,
1554    pub availability_zone: String,
1555    pub launch_type: String,
1556    #[serde(skip_serializing_if = "Option::is_none")]
1557    pub vpc_id: Option<String>,
1558    #[serde(skip_serializing_if = "Option::is_none")]
1559    pub eni_id: Option<String>,
1560}
1561
1562#[derive(Debug, Clone, Serialize, Deserialize)]
1563#[serde(rename_all = "camelCase")]
1564pub struct EcsTaskMetadataResponse {
1565    pub task: EcsTaskMetadata,
1566}
1567
1568// ── ELBv2 ───────────────────────────────────────────────────────────
1569
1570// ── CloudFront ──────────────────────────────────────────────────────
1571
1572#[derive(Debug, Clone, Serialize, Deserialize)]
1573#[serde(rename_all = "camelCase")]
1574pub struct CloudFrontDistribution {
1575    pub id: String,
1576    pub domain_name: String,
1577    pub enabled: bool,
1578    /// In-process data-plane listener port. `None` until the supervisor binds
1579    /// a listener for an enabled distribution (data-plane extension, not part
1580    /// of the AWS API surface).
1581    pub bound_port: Option<u16>,
1582}
1583
1584#[derive(Debug, Clone, Serialize, Deserialize)]
1585#[serde(rename_all = "camelCase")]
1586pub struct CloudFrontDistributionsResponse {
1587    pub distributions: Vec<CloudFrontDistribution>,
1588}
1589
1590#[derive(Debug, Clone, Serialize, Deserialize)]
1591#[serde(rename_all = "camelCase")]
1592pub struct Elbv2LoadBalancer {
1593    pub arn: String,
1594    pub name: String,
1595    pub dns_name: String,
1596    pub scheme: String,
1597    pub vpc_id: String,
1598    pub state_code: String,
1599    pub state_reason: Option<String>,
1600    pub lb_type: String,
1601    pub ip_address_type: String,
1602    pub availability_zones: Vec<Elbv2AvailabilityZone>,
1603    pub security_groups: Vec<String>,
1604    pub created_time: String,
1605    pub tags: Vec<Elbv2Tag>,
1606    /// In-process data plane TCP port for ALBs. `None` for NLB/GWLB
1607    /// or when the data plane is disabled. Tests connect to
1608    /// `127.0.0.1:<bound_port>` to reach the routed targets.
1609    #[serde(skip_serializing_if = "Option::is_none")]
1610    pub bound_port: Option<u16>,
1611}
1612
1613#[derive(Debug, Clone, Serialize, Deserialize)]
1614#[serde(rename_all = "camelCase")]
1615pub struct Elbv2AvailabilityZone {
1616    pub zone_name: String,
1617    pub subnet_id: String,
1618}
1619
1620#[derive(Debug, Clone, Serialize, Deserialize)]
1621#[serde(rename_all = "camelCase")]
1622pub struct Elbv2Tag {
1623    pub key: String,
1624    pub value: String,
1625}
1626
1627#[derive(Debug, Clone, Serialize, Deserialize)]
1628#[serde(rename_all = "camelCase")]
1629pub struct Elbv2LoadBalancersResponse {
1630    pub load_balancers: Vec<Elbv2LoadBalancer>,
1631}
1632
1633#[derive(Debug, Clone, Serialize, Deserialize)]
1634#[serde(rename_all = "camelCase")]
1635pub struct Elbv2TargetGroup {
1636    pub arn: String,
1637    pub name: String,
1638    pub protocol: Option<String>,
1639    pub port: Option<i32>,
1640    pub vpc_id: Option<String>,
1641    pub target_type: String,
1642    pub load_balancer_arns: Vec<String>,
1643    pub targets: Vec<Elbv2Target>,
1644    pub health_check_protocol: Option<String>,
1645    pub health_check_port: Option<String>,
1646    pub health_check_path: Option<String>,
1647    pub healthy_threshold_count: i32,
1648    pub unhealthy_threshold_count: i32,
1649    pub created_time: String,
1650    pub tags: Vec<Elbv2Tag>,
1651}
1652
1653#[derive(Debug, Clone, Serialize, Deserialize)]
1654#[serde(rename_all = "camelCase")]
1655pub struct Elbv2Target {
1656    pub id: String,
1657    pub port: Option<i32>,
1658    pub availability_zone: Option<String>,
1659    pub health_state: String,
1660    pub health_reason: Option<String>,
1661    pub health_description: Option<String>,
1662}
1663
1664#[derive(Debug, Clone, Serialize, Deserialize)]
1665#[serde(rename_all = "camelCase")]
1666pub struct Elbv2TargetGroupsResponse {
1667    pub target_groups: Vec<Elbv2TargetGroup>,
1668}
1669
1670#[derive(Debug, Clone, Serialize, Deserialize)]
1671#[serde(rename_all = "camelCase")]
1672pub struct Elbv2Listener {
1673    pub arn: String,
1674    pub load_balancer_arn: String,
1675    pub port: Option<i32>,
1676    pub protocol: Option<String>,
1677    pub ssl_policy: Option<String>,
1678    pub certificate_arns: Vec<String>,
1679    pub default_action_type: Option<String>,
1680    pub default_target_group_arn: Option<String>,
1681}
1682
1683#[derive(Debug, Clone, Serialize, Deserialize)]
1684#[serde(rename_all = "camelCase")]
1685pub struct Elbv2ListenersResponse {
1686    pub listeners: Vec<Elbv2Listener>,
1687}
1688
1689#[derive(Debug, Clone, Serialize, Deserialize)]
1690#[serde(rename_all = "camelCase")]
1691pub struct Elbv2Rule {
1692    pub arn: String,
1693    pub listener_arn: String,
1694    pub priority: String,
1695    pub is_default: bool,
1696    pub condition_fields: Vec<String>,
1697    pub action_type: Option<String>,
1698}
1699
1700#[derive(Debug, Clone, Serialize, Deserialize)]
1701#[serde(rename_all = "camelCase")]
1702pub struct Elbv2RulesResponse {
1703    pub rules: Vec<Elbv2Rule>,
1704}
1705
1706/// Request to bootstrap an IAM admin user in a specific account.
1707/// Used by `/_fakecloud/iam/create-admin` to solve the multi-account
1708/// bootstrap problem: there's no per-account root credential, so this
1709/// endpoint creates a user with full admin access in any account.
1710#[derive(Debug, Clone, Serialize, Deserialize)]
1711#[serde(rename_all = "camelCase")]
1712pub struct CreateAdminRequest {
1713    pub account_id: String,
1714    pub user_name: String,
1715}
1716
1717#[derive(Debug, Clone, Serialize, Deserialize)]
1718#[serde(rename_all = "camelCase")]
1719pub struct CreateAdminResponse {
1720    pub access_key_id: String,
1721    pub secret_access_key: String,
1722    pub account_id: String,
1723    pub arn: String,
1724}
1725
1726/// Body for `POST /_fakecloud/route53/health-checks/{id}/status`. The
1727/// admin endpoint flips a stored Route 53 health check's reported
1728/// status (and optionally the last-failure-reason observation) so
1729/// tests can simulate failover scenarios without a live checker.
1730#[derive(Debug, Clone, Serialize, Deserialize)]
1731#[serde(rename_all = "camelCase")]
1732pub struct Route53HealthCheckStatusRequest {
1733    /// New status reported by `GetHealthCheckStatus`. One of
1734    /// `"Success"`, `"Failure"`, `"Timeout"`, `"DnsError"`,
1735    /// `"InsufficientDataPoints"`, `"Unknown"`.
1736    pub status: Route53HealthCheckStatusValue,
1737    /// Optional last-failure observation surfaced by
1738    /// `GetHealthCheckLastFailureReason` and appended to the
1739    /// `<Status>` element for failure-flavoured statuses (`Failure`,
1740    /// `Timeout`, `DnsError`). Ignored when `status` is `Success`,
1741    /// `InsufficientDataPoints`, or `Unknown`. `None` leaves the prior
1742    /// value intact.
1743    #[serde(default)]
1744    pub reason: Option<String>,
1745}
1746
1747/// Discriminator for the admin `status` field. Mirrors the variants of
1748/// `fakecloud_route53::HealthCheckStatus` without forcing the SDK crate
1749/// to depend on the route53 crate.
1750#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1751pub enum Route53HealthCheckStatusValue {
1752    Success,
1753    Failure,
1754    Timeout,
1755    DnsError,
1756    InsufficientDataPoints,
1757    Unknown,
1758}
1759
1760/// Response body for `GET /_fakecloud/route53/zones/{id}/dnssec`. Surfaces
1761/// the deterministic ECDSA P-256 DNSSEC chain-of-trust material for a
1762/// hosted zone with at least one ACTIVE Key Signing Key. Real Route 53
1763/// keeps this material inside KMS; fakecloud derives it from the
1764/// `(zone_id, ksk_name)` pair so persistence reloads, multiple test
1765/// runs, and verifier code see stable values.
1766#[derive(Debug, Clone, Serialize, Deserialize)]
1767#[serde(rename_all = "camelCase")]
1768pub struct Route53DnssecMaterialResponse {
1769    /// Hosted zone the material belongs to (without the
1770    /// `/hostedzone/` prefix).
1771    pub hosted_zone_id: String,
1772    /// KSK name used to derive the keypair.
1773    pub key_signing_key_name: String,
1774    /// Algorithm number (always `13` for ECDSAP256SHA256).
1775    pub algorithm: u8,
1776    /// DNSKEY flags field (always `257` for a KSK).
1777    pub flags: u16,
1778    /// Standard DNSKEY key tag (RFC 4034 Appendix B).
1779    pub key_tag: u16,
1780    /// DNSKEY public-key wire bytes (`X || Y`, 64 bytes for P-256),
1781    /// base64-encoded — what would appear in the DNSKEY RDATA.
1782    pub dnskey_public_key_b64: String,
1783    /// SHA-256 DS digest hex over the canonical owner name + DNSKEY
1784    /// RDATA. Equivalent to what the parent zone publishes.
1785    pub ds_digest_sha256_hex: String,
1786}
1787
1788/// Body for `POST /_fakecloud/route53/zones/{id}/dnssec/sign`. Signs an
1789/// RRset under the zone's first ACTIVE KSK and returns the raw RRSIG
1790/// fields so tests can verify the signature against
1791/// `dnskey_public_key_b64` from `Route53DnssecMaterialResponse`.
1792#[derive(Debug, Clone, Serialize, Deserialize)]
1793#[serde(rename_all = "camelCase")]
1794pub struct Route53DnssecSignRequest {
1795    /// RRset owner name (e.g., `"www.example.com."`). Trailing dot
1796    /// optional — added if missing.
1797    pub name: String,
1798    /// Record type (`"A"`, `"AAAA"`, `"CNAME"`, `"TXT"`, ...).
1799    #[serde(rename = "type")]
1800    pub record_type: String,
1801    /// Original TTL field for the RRSIG.
1802    pub ttl: u32,
1803    /// One-or-more RDATA values matching what `ResourceRecord.Value`
1804    /// would carry on the wire.
1805    pub rdatas: Vec<String>,
1806}
1807
1808/// Response from the DNSSEC sign admin endpoint.
1809#[derive(Debug, Clone, Serialize, Deserialize)]
1810#[serde(rename_all = "camelCase")]
1811pub struct Route53DnssecSignResponse {
1812    /// Base64-encoded raw `r||s` ECDSA-P256 signature (64 bytes
1813    /// decoded).
1814    pub signature_b64: String,
1815    /// Algorithm number (always `13`).
1816    pub algorithm: u8,
1817    /// Key tag of the signing KSK.
1818    pub key_tag: u16,
1819    /// Owner name of the signer (the zone name).
1820    pub signer_name: String,
1821    /// Unix-time inception (signature validity start).
1822    pub inception: u32,
1823    /// Unix-time expiration (signature validity end).
1824    pub expiration: u32,
1825    /// Label count for the RRSIG `Labels` field.
1826    pub labels: u8,
1827    /// Original TTL echoed back from the request.
1828    pub original_ttl: u32,
1829    /// Record type echoed back from the request.
1830    #[serde(rename = "type")]
1831    pub rrset_type: String,
1832}
1833
1834/// Body for `POST /_fakecloud/acm/certificates/{arn-or-id}/status`. The
1835/// admin endpoint flips a stored ACM certificate's status (and
1836/// optionally records a failure reason) so tests can synchronously
1837/// drive a cert to `ISSUED`, `FAILED`, or `VALIDATION_TIMED_OUT`
1838/// without waiting on the auto-issue tick.
1839#[derive(Debug, Clone, Serialize, Deserialize)]
1840#[serde(rename_all = "camelCase")]
1841pub struct AcmCertificateStatusRequest {
1842    /// New certificate status. One of `"ISSUED"`, `"FAILED"`,
1843    /// `"VALIDATION_TIMED_OUT"`. Other ACM statuses are accepted as
1844    /// raw strings in case callers want to simulate a niche state.
1845    pub status: String,
1846    /// Optional failure reason surfaced as `FailureReason` in
1847    /// `DescribeCertificate`. Ignored when `status = ISSUED`. `None`
1848    /// leaves the prior value intact.
1849    #[serde(default)]
1850    pub reason: Option<String>,
1851}
1852
1853// ── Glue ────────────────────────────────────────────────────────────
1854
1855/// Curated row for `GET /_fakecloud/glue/jobs`. Mirrors the
1856/// configured Glue Job state so tests can assert what `CreateJob`
1857/// recorded without re-listing through the AWS surface.
1858#[derive(Debug, Clone, Serialize, Deserialize)]
1859#[serde(rename_all = "camelCase")]
1860pub struct GlueJob {
1861    pub account_id: String,
1862    pub name: String,
1863    pub role: String,
1864    pub command: serde_json::Value,
1865    pub default_arguments: std::collections::BTreeMap<String, String>,
1866    pub max_capacity: Option<f64>,
1867    pub max_retries: i64,
1868    pub timeout: Option<i64>,
1869    pub glue_version: Option<String>,
1870    pub worker_type: Option<String>,
1871    pub number_of_workers: Option<i64>,
1872    pub created_on: String,
1873    pub last_modified_on: String,
1874}
1875
1876/// Curated row for `GET /_fakecloud/glue/crawlers`. One entry per
1877/// crawler across every account, mirroring what `CreateCrawler`
1878/// recorded plus its lifecycle state.
1879#[derive(Debug, Clone, Serialize, Deserialize)]
1880#[serde(rename_all = "camelCase")]
1881pub struct GlueCrawler {
1882    pub account_id: String,
1883    pub name: String,
1884    pub role: String,
1885    #[serde(skip_serializing_if = "Option::is_none")]
1886    pub database_name: Option<String>,
1887    /// READY / RUNNING / STOPPING.
1888    pub state: String,
1889    /// Short summary of configured targets, e.g. "2 S3, 1 JDBC".
1890    pub target_summary: String,
1891    #[serde(skip_serializing_if = "Option::is_none")]
1892    pub schedule: Option<String>,
1893    pub creation_time: String,
1894    pub last_updated: String,
1895}
1896
1897#[derive(Debug, Clone, Serialize, Deserialize)]
1898#[serde(rename_all = "camelCase")]
1899pub struct GlueCrawlersResponse {
1900    pub crawlers: Vec<GlueCrawler>,
1901}
1902
1903// ── CloudWatch ──────────────────────────────────────────────────────
1904
1905/// A single metric dimension (name/value pair).
1906#[derive(Debug, Clone, Serialize, Deserialize)]
1907#[serde(rename_all = "camelCase")]
1908pub struct CloudWatchDimension {
1909    pub name: String,
1910    pub value: String,
1911}
1912
1913/// One alarm (metric or composite) as exposed by
1914/// `GET /_fakecloud/cloudwatch/alarms`. Metric-only fields
1915/// (`namespace`/`metricName`/`threshold`/`comparisonOperator`) are
1916/// omitted for composite alarms; `alarmRule` is present only for
1917/// composite alarms.
1918#[derive(Debug, Clone, Serialize, Deserialize)]
1919#[serde(rename_all = "camelCase")]
1920pub struct CloudWatchAlarm {
1921    pub account_id: String,
1922    pub region: String,
1923    pub name: String,
1924    /// "metric" or "composite".
1925    #[serde(rename = "type")]
1926    pub alarm_type: String,
1927    /// OK / ALARM / INSUFFICIENT_DATA.
1928    pub state: String,
1929    pub state_reason: String,
1930    #[serde(skip_serializing_if = "Option::is_none")]
1931    pub state_updated_timestamp: Option<String>,
1932    pub actions_enabled: bool,
1933    pub alarm_actions: Vec<String>,
1934    pub ok_actions: Vec<String>,
1935    pub insufficient_data_actions: Vec<String>,
1936    #[serde(skip_serializing_if = "Option::is_none")]
1937    pub namespace: Option<String>,
1938    #[serde(skip_serializing_if = "Option::is_none")]
1939    pub metric_name: Option<String>,
1940    #[serde(skip_serializing_if = "Option::is_none")]
1941    pub threshold: Option<f64>,
1942    #[serde(skip_serializing_if = "Option::is_none")]
1943    pub comparison_operator: Option<String>,
1944    #[serde(skip_serializing_if = "Option::is_none")]
1945    pub alarm_rule: Option<String>,
1946}
1947
1948#[derive(Debug, Clone, Serialize, Deserialize)]
1949#[serde(rename_all = "camelCase")]
1950pub struct CloudWatchAlarmsResponse {
1951    pub alarms: Vec<CloudWatchAlarm>,
1952}
1953
1954/// Latest datapoint summary for a metric series.
1955#[derive(Debug, Clone, Serialize, Deserialize)]
1956#[serde(rename_all = "camelCase")]
1957pub struct CloudWatchLatestDatapoint {
1958    pub timestamp: String,
1959    #[serde(skip_serializing_if = "Option::is_none")]
1960    pub value: Option<f64>,
1961    #[serde(skip_serializing_if = "Option::is_none")]
1962    pub unit: Option<String>,
1963}
1964
1965/// One unique metric series as exposed by
1966/// `GET /_fakecloud/cloudwatch/metrics`, keyed by
1967/// (account, region, namespace, metricName, dimensions).
1968#[derive(Debug, Clone, Serialize, Deserialize)]
1969#[serde(rename_all = "camelCase")]
1970pub struct CloudWatchMetric {
1971    pub account_id: String,
1972    pub region: String,
1973    pub namespace: String,
1974    pub metric_name: String,
1975    pub dimensions: Vec<CloudWatchDimension>,
1976    pub datapoint_count: usize,
1977    /// Most-recent datapoint, or `null` if the series has none.
1978    pub latest: Option<CloudWatchLatestDatapoint>,
1979}
1980
1981#[derive(Debug, Clone, Serialize, Deserialize)]
1982#[serde(rename_all = "camelCase")]
1983pub struct CloudWatchMetricsResponse {
1984    pub metrics: Vec<CloudWatchMetric>,
1985}
1986
1987// ── Firehose ────────────────────────────────────────────────────────
1988
1989/// Server-side encryption summary for a Firehose delivery stream as
1990/// exposed by `GET /_fakecloud/firehose/delivery-streams`. `status` is
1991/// `ENABLED`/`DISABLED`; `keyType`/`keyArn` are present only when a
1992/// customer-managed key is configured.
1993#[derive(Debug, Clone, Serialize, Deserialize)]
1994#[serde(rename_all = "camelCase")]
1995pub struct FirehoseEncryption {
1996    /// ENABLED / DISABLED.
1997    pub status: String,
1998    #[serde(skip_serializing_if = "Option::is_none")]
1999    pub key_type: Option<String>,
2000    #[serde(skip_serializing_if = "Option::is_none")]
2001    pub key_arn: Option<String>,
2002}
2003
2004/// One delivery stream as exposed by
2005/// `GET /_fakecloud/firehose/delivery-streams`. One entry per stream
2006/// across every account, mirroring what `CreateDeliveryStream` recorded
2007/// plus its lifecycle and encryption state.
2008#[derive(Debug, Clone, Serialize, Deserialize)]
2009#[serde(rename_all = "camelCase")]
2010pub struct FirehoseDeliveryStream {
2011    pub account_id: String,
2012    pub name: String,
2013    pub arn: String,
2014    /// DirectPut / KinesisStreamAsSource.
2015    pub stream_type: String,
2016    /// CREATING / ACTIVE / ...
2017    pub status: String,
2018    pub encryption: FirehoseEncryption,
2019    pub destination_count: usize,
2020    pub create_timestamp: String,
2021    #[serde(skip_serializing_if = "Option::is_none")]
2022    pub last_update_timestamp: Option<String>,
2023}
2024
2025#[derive(Debug, Clone, Serialize, Deserialize)]
2026#[serde(rename_all = "camelCase")]
2027pub struct FirehoseDeliveryStreamsResponse {
2028    pub delivery_streams: Vec<FirehoseDeliveryStream>,
2029}
2030
2031// ── Athena ──────────────────────────────────────────────────────────
2032
2033/// One row in the Athena named-query introspection list returned by
2034/// `GET /_fakecloud/athena/named-queries`. Mirrors the underlying named
2035/// query record plus a `last_used_at` timestamp the server bumps every
2036/// time `StartQueryExecution` resolves the query by id.
2037#[derive(Debug, Clone, Serialize, Deserialize)]
2038#[serde(rename_all = "camelCase")]
2039pub struct AthenaNamedQuery {
2040    pub named_query_id: String,
2041    pub name: String,
2042    #[serde(default)]
2043    pub description: Option<String>,
2044    pub database: String,
2045    pub query_string: String,
2046    pub workgroup: String,
2047    /// RFC3339 timestamp of the most recent `StartQueryExecution` that
2048    /// resolved its query string from this named query. `None` until the
2049    /// first such invocation.
2050    #[serde(default)]
2051    pub last_used_at: Option<String>,
2052}
2053
2054#[derive(Debug, Clone, Serialize, Deserialize)]
2055#[serde(rename_all = "camelCase")]
2056pub struct GlueJobsResponse {
2057    pub jobs: Vec<GlueJob>,
2058}
2059
2060/// Curated row for `GET /_fakecloud/glue/job-runs`. Includes the
2061/// full state machine of a JobRun (StartJobRun ledger). Filter by
2062/// `?job_name=foo` to scope to a single job.
2063#[derive(Debug, Clone, Serialize, Deserialize)]
2064#[serde(rename_all = "camelCase")]
2065pub struct GlueJobRun {
2066    pub account_id: String,
2067    pub id: String,
2068    pub job_name: String,
2069    pub attempt: i64,
2070    pub started_on: String,
2071    pub completed_on: Option<String>,
2072    pub job_run_state: String,
2073    pub arguments: std::collections::BTreeMap<String, String>,
2074    pub error_message: Option<String>,
2075    pub execution_time: i64,
2076}
2077
2078// ── Organizations ───────────────────────────────────────────────────
2079
2080/// A single member account as exposed by
2081/// `GET /_fakecloud/organizations/accounts`. Mirrors the AWS
2082/// Organizations `Account` shape but adds two fakecloud-only fields
2083/// useful for test assertions: `parentOuId` (resolved parent OU or
2084/// root) and `scpAttached` (the set of SCP IDs directly attached to
2085/// the account — does not walk up the hierarchy).
2086#[derive(Debug, Clone, Serialize, Deserialize)]
2087#[serde(rename_all = "camelCase")]
2088pub struct OrganizationsAccount {
2089    pub id: String,
2090    pub arn: String,
2091    pub email: String,
2092    pub name: String,
2093    /// AWS lifecycle state. One of `ACTIVE`, `SUSPENDED`,
2094    /// `PENDING_CLOSURE`.
2095    pub status: String,
2096    /// How the account entered the organization. One of `INVITED`,
2097    /// `CREATED`.
2098    pub joined_method: String,
2099    /// RFC3339 timestamp the account joined the org.
2100    pub joined_timestamp: String,
2101    /// Parent OU or root id. Always set for accounts attached to a
2102    /// live org; `None` only if the account record is mid-removal.
2103    #[serde(skip_serializing_if = "Option::is_none")]
2104    pub parent_ou_id: Option<String>,
2105    /// Tags directly attached to the account (alphabetical by key).
2106    #[serde(default)]
2107    pub tags: Vec<OrganizationsTag>,
2108    /// SCP ids directly attached to the account (alphabetical).
2109    /// Does not include policies inherited from parent OUs or root.
2110    #[serde(default)]
2111    pub scp_attached: Vec<String>,
2112}
2113
2114#[derive(Debug, Clone, Serialize, Deserialize)]
2115#[serde(rename_all = "camelCase")]
2116pub struct GlueJobRunsResponse {
2117    pub runs: Vec<GlueJobRun>,
2118}
2119
2120#[derive(Debug, Clone, Serialize, Deserialize)]
2121#[serde(rename_all = "camelCase")]
2122pub struct AthenaNamedQueriesResponse {
2123    pub queries: Vec<AthenaNamedQuery>,
2124}
2125
2126#[derive(Debug, Clone, Serialize, Deserialize)]
2127#[serde(rename_all = "camelCase")]
2128pub struct OrganizationsTag {
2129    pub key: String,
2130    pub value: String,
2131}
2132
2133/// Response body for `GET /_fakecloud/organizations/accounts`.
2134///
2135/// `managementAccountId` and `masterAccountId` are duplicates — AWS
2136/// renamed `Master` to `Management` in 2020 but kept the old field
2137/// around for back-compat. Both are returned here so SDKs in either
2138/// vintage match.
2139///
2140/// When no organization has been created yet, `accounts` is empty and
2141/// the account-id fields are `None`.
2142#[derive(Debug, Clone, Serialize, Deserialize)]
2143#[serde(rename_all = "camelCase")]
2144pub struct OrganizationsAccountsResponse {
2145    pub accounts: Vec<OrganizationsAccount>,
2146    #[serde(skip_serializing_if = "Option::is_none")]
2147    pub management_account_id: Option<String>,
2148    #[serde(skip_serializing_if = "Option::is_none")]
2149    pub master_account_id: Option<String>,
2150}
2151
2152/// One billing-responsibility transfer as exposed by
2153/// `GET /_fakecloud/organizations/responsibility-transfers`. Mirrors the
2154/// AWS `ResponsibilityTransfer` shape: `direction` is `INBOUND`/`OUTBOUND`,
2155/// `status` walks the transfer lifecycle, and `activeHandshakeId` points
2156/// at the handshake the invited org accepts/declines (or `null`).
2157#[derive(Debug, Clone, Serialize, Deserialize)]
2158#[serde(rename_all = "camelCase")]
2159pub struct OrganizationsResponsibilityTransfer {
2160    pub id: String,
2161    pub arn: String,
2162    pub name: String,
2163    #[serde(rename = "type")]
2164    pub transfer_type: String,
2165    pub status: String,
2166    /// INBOUND / OUTBOUND.
2167    pub direction: String,
2168    pub source_management_account_id: String,
2169    pub source_management_account_email: String,
2170    pub target_management_account_id: String,
2171    pub target_management_account_email: String,
2172    /// RFC3339 timestamp the transfer was initiated.
2173    pub start_timestamp: String,
2174    /// RFC3339 timestamp the transfer concluded, or `null` while open.
2175    #[serde(skip_serializing_if = "Option::is_none")]
2176    pub end_timestamp: Option<String>,
2177    #[serde(skip_serializing_if = "Option::is_none")]
2178    pub active_handshake_id: Option<String>,
2179}
2180
2181#[derive(Debug, Clone, Serialize, Deserialize)]
2182#[serde(rename_all = "camelCase")]
2183pub struct OrganizationsResponsibilityTransfersResponse {
2184    pub responsibility_transfers: Vec<OrganizationsResponsibilityTransfer>,
2185}
2186
2187/// Body for `POST /_fakecloud/cloudfront/distributions/{id}/status`. The
2188/// admin endpoint flips a stored CloudFront Distribution's status so
2189/// tests can synchronously force it into `Deployed` or `InProgress`
2190/// without waiting on the propagation tick.
2191#[derive(Debug, Clone, Serialize, Deserialize)]
2192#[serde(rename_all = "camelCase")]
2193pub struct CloudFrontDistributionStatusRequest {
2194    /// New distribution status. Typically `"Deployed"` or `"InProgress"`.
2195    pub status: String,
2196}
2197
2198// ── ACM (introspection) ─────────────────────────────────────────────
2199
2200/// Response body for `GET /_fakecloud/acm/certificates/{arn-or-id}/chain-info`.
2201/// Reports PEM block/byte counts and a `status` / `cert_type` snapshot
2202/// so tests can verify that uploaded chains round-trip intact. The
2203/// `external_ca_validated` flag is always `false` to document that
2204/// fakecloud does not run real X.509 verification.
2205#[derive(Debug, Clone, Serialize, Deserialize)]
2206#[serde(rename_all = "snake_case")]
2207pub struct AcmCertificateChainInfo {
2208    pub certificate_arn: String,
2209    pub certificate_pem_bytes: u64,
2210    pub certificate_pem_blocks: u64,
2211    pub chain_pem_bytes: u64,
2212    pub chain_pem_blocks: u64,
2213    pub external_ca_validated: bool,
2214    pub status: String,
2215    pub cert_type: String,
2216}
2217
2218// ── Cognito extras ──────────────────────────────────────────────────
2219
2220/// Response from `POST /_fakecloud/cognito/compromised-passwords`. Echoes
2221/// the count of *new* password hashes added to the compromised-credentials
2222/// set on this call.
2223#[derive(Debug, Clone, Serialize, Deserialize)]
2224#[serde(rename_all = "camelCase")]
2225pub struct CompromisedPasswordsResponse {
2226    pub added: u64,
2227}
2228
2229/// One registered WebAuthn credential surfaced by
2230/// `GET /_fakecloud/cognito/webauthn-credentials`. `attestation_info` is
2231/// kept as raw JSON because its shape depends on the attestation format.
2232#[derive(Debug, Clone, Serialize, Deserialize)]
2233pub struct WebAuthnCredential {
2234    pub account_id: String,
2235    pub pool_user: String,
2236    pub credential_id: String,
2237    pub relying_party_id: String,
2238    pub attestation_info: serde_json::Value,
2239}
2240
2241#[derive(Debug, Clone, Serialize, Deserialize)]
2242pub struct WebAuthnCredentialsResponse {
2243    pub credentials: Vec<WebAuthnCredential>,
2244}
2245
2246// ── SES extras (admin responses) ────────────────────────────────────
2247
2248/// Response from `POST /_fakecloud/ses/identities/{name}/mail-from-status`.
2249#[derive(Debug, Clone, Serialize, Deserialize)]
2250#[serde(rename_all = "camelCase")]
2251pub struct SesMailFromStatusResponse {
2252    pub identity: String,
2253    pub mail_from_domain_status: String,
2254}
2255
2256/// Response from `GET /_fakecloud/ses/identities/{name}/dkim-public-key`.
2257#[derive(Debug, Clone, Serialize, Deserialize)]
2258#[serde(rename_all = "camelCase")]
2259pub struct SesDkimPublicKeyResponse {
2260    pub identity: String,
2261    pub selector: String,
2262    pub public_key_base64: String,
2263    pub signing_enabled: bool,
2264}
2265
2266/// Response from `POST /_fakecloud/ses/account/sandbox`.
2267#[derive(Debug, Clone, Serialize, Deserialize)]
2268#[serde(rename_all = "camelCase")]
2269pub struct SesSandboxResponse {
2270    pub sandbox: bool,
2271    pub production_access_enabled: bool,
2272}
2273
2274/// Response from `GET /_fakecloud/ses/metrics`. fakecloud surfaces a
2275/// running `suppressedDropsTotal` counter so test code can verify that
2276/// the suppression list short-circuits sends.
2277#[derive(Debug, Clone, Serialize, Deserialize)]
2278#[serde(rename_all = "camelCase")]
2279pub struct SesMetricsResponse {
2280    pub suppressed_drops_total: u64,
2281}
2282
2283// ── ELBv2 admin ─────────────────────────────────────────────────────
2284
2285/// Response from `POST /_fakecloud/elbv2/access-logs/flush`. `flushed`
2286/// is the number of access-log records flushed to the configured S3
2287/// bucket on this call.
2288#[derive(Debug, Clone, Serialize, Deserialize)]
2289#[serde(rename_all = "camelCase")]
2290pub struct Elbv2AccessLogsFlushResponse {
2291    pub flushed: u64,
2292}
2293
2294// ── API Gateway v2 WebSocket connections ────────────────────────────
2295
2296/// Single active WebSocket connection tracked by the API Gateway v2
2297/// fake. Returned by `GET /_fakecloud/apigatewayv2/connections`.
2298#[derive(Debug, Clone, Serialize, Deserialize)]
2299#[serde(rename_all = "camelCase")]
2300pub struct ApiGatewayV2Connection {
2301    pub connection_id: String,
2302    pub api_id: String,
2303    pub stage: String,
2304    pub connected_at: String,
2305    pub last_active_at: String,
2306    pub source_ip: String,
2307}
2308
2309#[derive(Debug, Clone, Serialize, Deserialize)]
2310#[serde(rename_all = "camelCase")]
2311pub struct ApiGatewayV2ConnectionsResponse {
2312    pub connections: Vec<ApiGatewayV2Connection>,
2313}
2314
2315// ── ECS task IAM credentials ────────────────────────────────────────
2316
2317/// Response shape for `GET /_fakecloud/ecs/creds/{task_id}`. Matches the
2318/// real ECS task metadata credential endpoint field casing (PascalCase),
2319/// so this type is `Deserialize` only — fakecloud writes the keys
2320/// already capitalized.
2321#[derive(Debug, Clone, Serialize, Deserialize)]
2322pub struct EcsTaskCredentialsResponse {
2323    #[serde(rename = "AccessKeyId")]
2324    pub access_key_id: String,
2325    #[serde(rename = "SecretAccessKey")]
2326    pub secret_access_key: String,
2327    #[serde(rename = "Token")]
2328    pub token: String,
2329    #[serde(rename = "Expiration")]
2330    pub expiration: String,
2331    #[serde(rename = "RoleArn")]
2332    pub role_arn: String,
2333}
2334
2335// ── KMS usage (admin) ───────────────────────────────────────────────
2336
2337/// One recorded KMS data-plane invocation, exposed by
2338/// `GET /_fakecloud/kms/usage`. Fields mirror the JSON payload emitted
2339/// by the server's usage recorder.
2340#[derive(Debug, Clone, Serialize, Deserialize)]
2341#[serde(rename_all = "camelCase")]
2342pub struct KmsUsageRecord {
2343    pub timestamp: String,
2344    pub operation: String,
2345    pub service_principal: Option<String>,
2346    pub account_id: String,
2347    pub key_arn: String,
2348    pub encryption_context: Option<serde_json::Value>,
2349}
2350
2351#[derive(Debug, Clone, Serialize, Deserialize)]
2352#[serde(rename_all = "camelCase")]
2353pub struct KmsUsageResponse {
2354    pub records: Vec<KmsUsageRecord>,
2355}
2356
2357// ── ELBv2 WAF counts (admin) ────────────────────────────────────────
2358
2359/// Response body for `GET /_fakecloud/elbv2/waf-counts`. The exact
2360/// shape of `counts` is service-internal and intentionally left as
2361/// free-form JSON so we don't have to track every new dimension in
2362/// the SDK.
2363#[derive(Debug, Clone, Serialize, Deserialize)]
2364#[serde(rename_all = "camelCase")]
2365pub struct Elbv2WafCountsResponse {
2366    pub counts: serde_json::Value,
2367}
2368
2369// ── EC2 instances (introspection) ───────────────────────────────────
2370
2371/// A single EC2 instance as surfaced by `GET /_fakecloud/ec2/instances`.
2372/// One EC2 instance's control-plane view, plus the backing container handle
2373/// when the instance is backed by a real container runtime (Docker container
2374/// id or Kubernetes Pod name); `container_id` is `None` in metadata-only mode.
2375#[derive(Debug, Clone, Serialize, Deserialize)]
2376#[serde(rename_all = "camelCase")]
2377pub struct Ec2Instance {
2378    pub instance_id: String,
2379    pub image_id: String,
2380    pub instance_type: String,
2381    /// EC2 state name: `pending` | `running` | `shutting-down` |
2382    /// `terminated` | `stopping` | `stopped`.
2383    pub state: String,
2384    pub private_ip: String,
2385    pub public_ip: Option<String>,
2386    pub subnet_id: Option<String>,
2387    pub vpc_id: Option<String>,
2388    pub key_name: Option<String>,
2389    pub security_group_ids: Vec<String>,
2390    pub availability_zone: String,
2391    pub launch_time: String,
2392    /// Backing container id (Docker) or Pod name (k8s); `None` when the
2393    /// instance runs metadata-only (no container runtime available).
2394    #[serde(default)]
2395    pub container_id: Option<String>,
2396}
2397
2398/// Response body for `GET /_fakecloud/ec2/instances`.
2399#[derive(Debug, Clone, Serialize, Deserialize)]
2400#[serde(rename_all = "camelCase")]
2401pub struct Ec2InstancesResponse {
2402    pub instances: Vec<Ec2Instance>,
2403}
2404
2405/// The real backing network of one EC2 instance — a debugging aid for "why
2406/// can't X reach Y" (issue #1745). Exposes which daemon network / NetworkPolicy
2407/// backs the instance, its container IP, and whether security-group enforcement
2408/// is active or degraded to metadata-only.
2409#[derive(Debug, Clone, Serialize, Deserialize)]
2410#[serde(rename_all = "camelCase")]
2411pub struct Ec2InstanceNetwork {
2412    pub instance_id: String,
2413    pub vpc_id: Option<String>,
2414    pub subnet_id: Option<String>,
2415    /// The instance's address on its backing network.
2416    pub private_ip: String,
2417    /// The Docker/Podman network (`fakecloud-subnet-<id>`) or k8s NetworkPolicy
2418    /// (`fakecloud-ec2-<id>`) backing the instance. `None` when metadata-only
2419    /// (no container runtime) or not yet running.
2420    pub backing_network: Option<String>,
2421    /// `docker` | `podman` | `kubernetes` | `none`.
2422    pub isolation_backend: String,
2423    /// Security-group enforcement mechanism: `nftables` | `networkpolicy` |
2424    /// `disabled`.
2425    pub security_group_enforcement: String,
2426    /// Whether security-group rules are actually enforced (vs tracked-only).
2427    pub enforcement_active: bool,
2428}
2429
2430/// Response body for `GET /_fakecloud/ec2/instance-networks`.
2431#[derive(Debug, Clone, Serialize, Deserialize)]
2432#[serde(rename_all = "camelCase")]
2433pub struct Ec2InstanceNetworksResponse {
2434    pub instance_networks: Vec<Ec2InstanceNetwork>,
2435}