runbeam_sdk/runbeam_api/
resources.rs

1use serde::{Deserialize, Serialize};
2
3// ========================================================================================
4// SHARED CONFIGURATION STRUCTURES
5// ========================================================================================
6
7/// Normalized connection configuration shared across peers, targets, endpoints, and backends
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ConnectionConfig {
10    #[serde(default)]
11    pub host: Option<String>,
12    #[serde(default)]
13    pub port: Option<u16>,
14    #[serde(default)]
15    pub protocol: Option<String>,
16    #[serde(default)]
17    pub base_path: Option<String>,
18}
19
20
21// ========================================================================================
22// PAGINATED RESPONSE STRUCTURES
23// ========================================================================================
24
25/// Paginated response wrapper
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct PaginatedResponse<T> {
28    pub data: Vec<T>,
29    #[serde(default)]
30    pub links: Option<PaginationLinks>,
31    #[serde(default)]
32    pub meta: Option<PaginationMeta>,
33}
34
35/// Pagination links
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct PaginationLinks {
38    pub first: Option<String>,
39    pub last: Option<String>,
40    pub prev: Option<String>,
41    pub next: Option<String>,
42}
43
44/// Pagination metadata
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct PaginationMeta {
47    pub current_page: u32,
48    pub from: Option<u32>,
49    pub last_page: u32,
50    #[serde(default)]
51    pub links: Option<Vec<serde_json::Value>>, // Laravel pagination links array
52    pub path: Option<String>,
53    pub per_page: u32,
54    pub to: Option<u32>,
55    pub total: u32,
56}
57
58/// Single resource response wrapper
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct ResourceResponse<T> {
61    pub data: T,
62}
63
64// ========================================================================================
65// RESOURCE TYPES
66// ========================================================================================
67
68/// Peer resource - represents external systems that send requests to Harmony
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Peer {
71    #[serde(rename = "type")]
72    pub resource_type: String,
73    #[serde(default)]
74    pub id: Option<String>,
75    pub code: String,
76    pub name: String,
77    pub team_id: String,
78    pub gateway_id: Option<String>,
79    #[serde(default)]
80    pub connection: Option<ConnectionConfig>,
81    /// Protocol type - the type of protocol used by this peer (http, https, dicom, etc.)
82    #[serde(default)]
83    pub protocol: Option<String>,
84    #[serde(default)]
85    pub description: Option<String>,
86    #[serde(default)]
87    pub enabled: Option<bool>,
88    /// Reference to an authentication defined in main config
89    #[serde(default)]
90    pub authentication: Option<String>,
91    #[serde(default)]
92    pub tags: Option<Vec<String>>,
93    #[serde(default)]
94    pub timeout_secs: Option<u32>,
95    #[serde(default)]
96    pub max_retries: Option<u32>,
97    #[serde(default)]
98    pub created_at: Option<String>,
99    #[serde(default)]
100    pub updated_at: Option<String>,
101}
102
103/// Target resource - represents external systems that receive requests from Harmony
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct Target {
106    #[serde(rename = "type")]
107    pub resource_type: String,
108    #[serde(default)]
109    pub id: Option<String>,
110    pub code: String,
111    pub name: String,
112    pub team_id: String,
113    pub gateway_id: Option<String>,
114    #[serde(default)]
115    pub connection: Option<ConnectionConfig>,
116    /// Protocol type - the type of protocol used by this target (http, https, dicom, etc.)
117    #[serde(default)]
118    pub protocol: Option<String>,
119    #[serde(default)]
120    pub description: Option<String>,
121    #[serde(default)]
122    pub enabled: Option<bool>,
123    /// Reference to an authentication defined in main config
124    #[serde(default)]
125    pub authentication: Option<String>,
126    #[serde(default)]
127    pub tags: Option<Vec<String>>,
128    #[serde(default)]
129    pub timeout_secs: Option<u32>,
130    #[serde(default)]
131    pub max_retries: Option<u32>,
132    #[serde(default)]
133    pub created_at: Option<String>,
134    #[serde(default)]
135    pub updated_at: Option<String>,
136}
137
138/// Gateway resource
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct Gateway {
141    #[serde(rename = "type")]
142    pub resource_type: String,
143    #[serde(default)]
144    pub id: Option<String>,
145    pub code: String,
146    pub name: String,
147    pub team_id: String,
148    pub enabled: Option<bool>,
149    #[serde(default)]
150    pub pipelines_path: Option<String>,
151    #[serde(default)]
152    pub transforms_path: Option<String>,
153    #[serde(default)]
154    pub jwks_cache_duration_hours: Option<u32>,
155    #[serde(default)]
156    pub management_enabled: Option<bool>,
157    #[serde(default)]
158    pub management_base_path: Option<String>,
159    #[serde(default)]
160    pub management_network_id: Option<String>,
161    #[serde(default)]
162    pub dns: Option<Vec<String>>,
163    #[serde(default)]
164    pub settings: Option<serde_json::Value>,
165    #[serde(default)]
166    pub created_at: Option<String>,
167    #[serde(default)]
168    pub updated_at: Option<String>,
169}
170
171/// User who authorized a gateway
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct AuthorizedByInfo {
174    pub id: String,
175    pub name: String,
176    pub email: String,
177}
178
179/// Service resource
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct Service {
182    #[serde(rename = "type")]
183    pub resource_type: String,
184    #[serde(default)]
185    pub id: Option<String>,
186    pub code: String,
187    pub name: String,
188    pub team_id: String,
189    pub gateway_id: String,
190    #[serde(default)]
191    pub description: Option<String>,
192    #[serde(default)]
193    pub created_at: Option<String>,
194    #[serde(default)]
195    pub updated_at: Option<String>,
196}
197
198/// Endpoint resource
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct Endpoint {
201    #[serde(rename = "type")]
202    pub resource_type: String,
203    #[serde(default)]
204    pub id: Option<String>,
205    pub code: String,
206    pub name: String,
207    pub team_id: String,
208    pub gateway_id: Option<String>,
209    #[serde(default)]
210    pub service_id: Option<String>,
211    /// Reference to a peer defined in main config (inherits peer's connection settings)
212    #[serde(default)]
213    pub peer_ref: Option<String>,
214    /// Connection configuration (overrides peer_ref settings if both specified)
215    #[serde(default)]
216    pub connection: Option<ConnectionConfig>,
217    /// Authentication reference (overrides peer_ref settings if both specified)
218    #[serde(default)]
219    pub authentication: Option<String>,
220    #[serde(default)]
221    pub path: Option<String>,
222    #[serde(default)]
223    pub methods: Option<Vec<String>>,
224    #[serde(default)]
225    pub description: Option<String>,
226    /// Service-specific options (highest precedence)
227    #[serde(default)]
228    pub options: Option<serde_json::Value>,
229    #[serde(default)]
230    pub created_at: Option<String>,
231    #[serde(default)]
232    pub updated_at: Option<String>,
233}
234
235/// Backend resource
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct Backend {
238    #[serde(rename = "type")]
239    pub resource_type: String,
240    #[serde(default)]
241    pub id: Option<String>,
242    pub code: String,
243    pub name: String,
244    pub team_id: String,
245    pub gateway_id: Option<String>,
246    #[serde(default)]
247    pub service_id: Option<String>,
248    /// Reference to a target defined in main config (inherits target's connection settings)
249    #[serde(default)]
250    pub target_ref: Option<String>,
251    /// Connection configuration (overrides target_ref settings if both specified)
252    #[serde(default)]
253    pub connection: Option<ConnectionConfig>,
254    /// Authentication reference (overrides target_ref settings if both specified)
255    #[serde(default)]
256    pub authentication: Option<String>,
257    #[serde(default)]
258    pub url: Option<String>,
259    #[serde(default)]
260    pub timeout_seconds: Option<u32>,
261    /// Maximum retry attempts (overrides target_ref.max_retries)
262    #[serde(default)]
263    pub max_retries: Option<u32>,
264    /// Service-specific options (highest precedence)
265    #[serde(default)]
266    pub options: Option<serde_json::Value>,
267    #[serde(default)]
268    pub created_at: Option<String>,
269    #[serde(default)]
270    pub updated_at: Option<String>,
271}
272
273/// Pipeline resource
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct Pipeline {
276    #[serde(rename = "type")]
277    pub resource_type: String,
278    #[serde(default)]
279    pub id: Option<String>,
280    pub code: String,
281    pub name: String,
282    pub description: String,
283    pub team_id: String,
284    pub gateway_id: Option<String>,
285    #[serde(default)]
286    pub networks: Option<Vec<String>>,
287    #[serde(default)]
288    pub endpoints: Option<serde_json::Value>,
289    #[serde(default)]
290    pub backends: Option<serde_json::Value>,
291    #[serde(default)]
292    pub middleware: Option<serde_json::Value>,
293    #[serde(default)]
294    pub created_at: Option<String>,
295    #[serde(default)]
296    pub updated_at: Option<String>,
297}
298
299/// Middleware resource  
300#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct Middleware {
302    #[serde(rename = "type")]
303    pub resource_type: String,
304    #[serde(default)]
305    pub id: Option<String>,
306    pub code: String,
307    pub name: String,
308    pub team_id: String,
309    pub middleware_type: String,
310    /// Reference to an authentication defined in main config
311    #[serde(default)]
312    pub authentication: Option<String>,
313    #[serde(default)]
314    pub options: Option<serde_json::Value>,
315    #[serde(default)]
316    pub created_at: Option<String>,
317    #[serde(default)]
318    pub updated_at: Option<String>,
319}
320
321/// Transform resource
322#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct Transform {
324    #[serde(rename = "type")]
325    pub resource_type: String,
326    #[serde(default)]
327    pub id: Option<String>,
328    pub code: String,
329    pub name: String,
330    pub team_id: String,
331    pub gateway_id: String,
332    #[serde(default)]
333    pub options: Option<TransformOptions>,
334    #[serde(default)]
335    pub created_at: Option<String>,
336    #[serde(default)]
337    pub updated_at: Option<String>,
338}
339
340/// Transform options
341#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct TransformOptions {
343    pub instructions: Option<String>,
344}
345
346/// Array of rule IDs for a policy.
347///
348/// In harmony-dsl v1.7.0+, policies reference rules by ID using a simple array of strings.
349/// Each ID in this array corresponds to a top-level `[rules.*]` table definition.
350///
351/// # Example
352///
353/// ```json
354/// ["rate_limit_rule_1", "rate_limit_rule_2", "allow_internal"]
355/// ```
356#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
357pub struct PolicyRules(pub Vec<String>);
358
359impl PolicyRules {
360    /// Create a new PolicyRules from a vector of rule IDs
361    pub fn new(rules: Vec<String>) -> Self {
362        PolicyRules(rules)
363    }
364
365    /// Get a reference to the underlying rule IDs
366    pub fn rules(&self) -> &[String] {
367        &self.0
368    }
369
370    /// Convert into the underlying vector of rule IDs
371    pub fn into_inner(self) -> Vec<String> {
372        self.0
373    }
374}
375
376/// Rule resource
377///
378/// Represents a rule definition that can be referenced by policies.
379/// Rules define access control logic with configurable options.
380#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct Rule {
382    #[serde(rename = "type")]
383    pub resource_type: String,
384    pub id: String,
385    pub code: String,
386    #[serde(default)]
387    pub name: Option<String>,
388    pub rule_type: String,
389    pub team_id: String,
390    pub gateway_id: String,
391    #[serde(default)]
392    pub weight: Option<u32>,
393    #[serde(default)]
394    pub enabled: Option<bool>,
395    #[serde(default)]
396    pub options: Option<serde_json::Value>,
397    #[serde(default)]
398    pub created_at: Option<String>,
399    #[serde(default)]
400    pub updated_at: Option<String>,
401}
402
403/// Policy resource
404///
405/// Represents a policy that contains references to rules.
406/// In v1.7.0+, rules are defined as top-level resources and referenced by ID.
407///
408/// # Example (v1.7.0 format)
409///
410/// ```json
411/// {
412///   "type": "policy",
413///   "id": "policy-123",
414///   "code": "rate-limit",
415///   "name": "Rate Limiting Policy",
416///   "enabled": 1,
417///   "team_id": "team-456",
418///   "gateway_id": "gateway-789",
419///   "rules": ["rate_limit_rule_1", "rate_limit_rule_2"],
420///   "created_at": "2024-01-01T00:00:00Z",
421///   "updated_at": "2024-01-01T00:00:00Z"
422/// }
423/// ```
424///
425/// # Breaking Change (v1.6.0 → v1.7.0)
426///
427/// In v1.7.0, the `rules` field format changed from nested objects to an array of rule ID strings.
428/// This aligns with the new flat/reusable policies and rules structure in harmony-dsl.
429#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct Policy {
431    #[serde(rename = "type")]
432    pub resource_type: String,
433    #[serde(default)]
434    pub id: Option<String>,
435    pub code: String,
436    pub name: String,
437    pub enabled: u32,
438    pub team_id: String,
439    pub gateway_id: String,
440    /// Array of rule IDs referenced by this policy.
441    ///
442    /// In v1.7.0+, rules are defined as top-level `[rules.*]` tables and referenced by ID.
443    /// Each ID in this array should correspond to a rule defined at the top level.
444    /// Rules are represented as a typed array of string IDs for better type safety.
445    #[serde(default)]
446    pub rules: Option<PolicyRules>,
447    #[serde(default)]
448    pub created_at: Option<String>,
449    #[serde(default)]
450    pub updated_at: Option<String>,
451}
452
453/// Network resource
454#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct Network {
456    #[serde(rename = "type")]
457    pub resource_type: String,
458    #[serde(default)]
459    pub id: Option<String>,
460    pub code: String,
461    pub name: String,
462    pub team_id: String,
463    pub gateway_id: Option<String>,
464    pub enable_wireguard: bool,
465    #[serde(default)]
466    pub interface: Option<String>,
467    #[serde(default, alias = "http")]
468    pub tcp_config: Option<TcpConfig>,
469    #[serde(default)]
470    pub created_at: Option<String>,
471    #[serde(default)]
472    pub updated_at: Option<String>,
473}
474
475/// TCP configuration for network - used by all protocol adapters (HTTP, DIMSE, etc.)
476#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct TcpConfig {
478    pub bind_address: Option<String>,
479    pub bind_port: Option<u16>,
480}
481
482/// Runbeam Cloud integration configuration
483#[derive(Debug, Clone, Serialize, Deserialize)]
484pub struct Runbeam {
485    #[serde(rename = "type")]
486    pub resource_type: String,
487    #[serde(default)]
488    pub id: Option<String>,
489    pub code: String,
490    pub name: String,
491    pub team_id: String,
492    pub gateway_id: Option<String>,
493    #[serde(default)]
494    pub enabled: Option<bool>,
495    #[serde(default)]
496    pub cloud_api_base_url: Option<String>,
497    #[serde(default)]
498    pub poll_interval_secs: Option<u32>,
499    #[serde(default)]
500    pub created_at: Option<String>,
501    #[serde(default)]
502    pub updated_at: Option<String>,
503}
504
505/// Authentication resource
506#[derive(Debug, Clone, Serialize, Deserialize)]
507pub struct Authentication {
508    #[serde(rename = "type")]
509    pub resource_type: String,
510    #[serde(default)]
511    pub id: Option<String>,
512    pub code: Option<String>,
513    pub name: String,
514    pub team_id: Option<String>,
515    pub gateway_id: Option<String>,
516    pub method: String,
517    #[serde(default)]
518    pub options: Option<serde_json::Value>,
519    #[serde(default)]
520    pub created_at: Option<String>,
521    #[serde(default)]
522    pub updated_at: Option<String>,
523}
524
525/// Full gateway configuration (for downloading complete config)
526#[derive(Debug, Clone, Serialize, Deserialize)]
527pub struct GatewayConfiguration {
528    pub gateway: Gateway,
529    #[serde(default)]
530    pub peers: Vec<Peer>,
531    #[serde(default)]
532    pub targets: Vec<Target>,
533    #[serde(default)]
534    pub services: Vec<Service>,
535    #[serde(default)]
536    pub endpoints: Vec<Endpoint>,
537    #[serde(default)]
538    pub backends: Vec<Backend>,
539    #[serde(default)]
540    pub pipelines: Vec<Pipeline>,
541    #[serde(default)]
542    pub middlewares: Vec<Middleware>,
543    #[serde(default)]
544    pub transforms: Vec<Transform>,
545    #[serde(default)]
546    pub policies: Vec<Policy>,
547    #[serde(default)]
548    pub rules: Vec<Rule>,
549    #[serde(default)]
550    pub networks: Vec<Network>,
551    #[serde(default)]
552    pub runbeam: Option<Runbeam>,
553    #[serde(default)]
554    pub authentications: Vec<Authentication>,
555}
556
557/// Change resource for configuration change tracking (API v1.0)
558///
559/// This represents a configuration change that needs to be applied to a gateway.
560/// The API returns two different levels of detail:
561///
562/// 1. ChangeMetadata (list view) - returned from `/api/harmony/changes` endpoints
563///    Contains: id, status, type, gateway_id, created_at
564///
565/// 2. ChangeResource (detail view) - returned from `/api/harmony/changes/{change}` endpoint  
566///    Contains all metadata fields plus: pipeline_id, toml_config, metadata, timestamps, error info
567#[derive(Debug, Clone, Serialize, Deserialize)]
568pub struct Change {
569    pub id: String,
570    #[serde(default)]
571    pub status: Option<String>,
572    #[serde(rename = "type")]
573    pub resource_type: String,
574    pub gateway_id: String,
575    #[serde(default)]
576    pub pipeline_id: Option<String>,
577    /// TOML configuration content (only present in detail view)
578    #[serde(default)]
579    pub toml_config: Option<String>,
580    /// Additional metadata (only present in detail view)
581    #[serde(default)]
582    pub metadata: Option<serde_json::Value>,
583    pub created_at: String,
584    #[serde(default)]
585    pub acknowledged_at: Option<String>,
586    #[serde(default)]
587    pub applied_at: Option<String>,
588    #[serde(default)]
589    pub failed_at: Option<String>,
590    #[serde(default)]
591    pub error_message: Option<String>,
592    #[serde(default)]
593    pub error_details: Option<serde_json::Value>,
594}
595
596/// Response from the base URL discovery endpoint
597#[derive(Debug, Clone, Serialize, Deserialize)]
598pub struct BaseUrlResponse {
599    /// Base URL for the Harmony API (e.g., https://runbeam.lndo.site/api)
600    pub base_url: String,
601    /// Optional path for changes API (e.g., "/")
602    #[serde(default)]
603    pub changes_path: Option<String>,
604    /// Optional fully resolved URL (base_url + changes_path)
605    #[serde(default)]
606    pub full_url: Option<String>,
607}
608
609/// Request payload for acknowledging multiple changes
610#[derive(Debug, Clone, Serialize, Deserialize)]
611pub struct AcknowledgeChangesRequest {
612    pub change_ids: Vec<String>,
613}
614
615/// Request payload for reporting a failed change
616#[derive(Debug, Clone, Serialize, Deserialize)]
617pub struct ChangeFailedRequest {
618    pub error: String,
619    #[serde(skip_serializing_if = "Option::is_none")]
620    pub details: Option<Vec<String>>,
621}
622
623/// Response from acknowledging multiple changes
624#[derive(Debug, Clone, Serialize, Deserialize)]
625pub struct AcknowledgeChangesResponse {
626    pub acknowledged: Vec<String>,
627    pub failed: Vec<String>,
628}
629
630/// Response from marking a change as applied or failed
631#[derive(Debug, Clone, Serialize, Deserialize)]
632pub struct ChangeStatusResponse {
633    pub success: bool,
634    pub message: String,
635}
636
637/// Type alias for change applied response
638pub type ChangeAppliedResponse = ChangeStatusResponse;
639
640/// Type alias for change failed response  
641pub type ChangeFailedResponse = ChangeStatusResponse;
642
643// ========================================================================================
644// MESH AUTHENTICATION
645// ========================================================================================
646
647/// Request payload for mesh token
648#[derive(Debug, Clone, Serialize, Deserialize)]
649pub struct MeshTokenRequest {
650    /// The mesh ID to authenticate against
651    pub mesh_id: String,
652    /// The destination URL the token is being requested for
653    pub destination_url: String,
654}
655
656/// Response from mesh token request
657#[derive(Debug, Clone, Serialize, Deserialize)]
658pub struct MeshTokenResponse {
659    /// The signed JWT token
660    pub token: String,
661    /// When the token expires (ISO 8601 format)
662    pub expires_at: String,
663    /// The mesh ID this token is valid for
664    pub mesh_id: String,
665}