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/// Authentication configuration shared across peers, targets, endpoints, and backends
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct AuthenticationConfig {
23    #[serde(default)]
24    pub method: Option<String>,
25    #[serde(default)]
26    pub credentials_path: Option<String>,
27}
28
29// ========================================================================================
30// PAGINATED RESPONSE STRUCTURES
31// ========================================================================================
32
33/// Paginated response wrapper
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct PaginatedResponse<T> {
36    pub data: Vec<T>,
37    #[serde(default)]
38    pub links: Option<PaginationLinks>,
39    #[serde(default)]
40    pub meta: Option<PaginationMeta>,
41}
42
43/// Pagination links
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct PaginationLinks {
46    pub first: Option<String>,
47    pub last: Option<String>,
48    pub prev: Option<String>,
49    pub next: Option<String>,
50}
51
52/// Pagination metadata
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct PaginationMeta {
55    pub current_page: u32,
56    pub from: Option<u32>,
57    pub last_page: u32,
58    #[serde(default)]
59    pub links: Option<Vec<serde_json::Value>>, // Laravel pagination links array
60    pub path: Option<String>,
61    pub per_page: u32,
62    pub to: Option<u32>,
63    pub total: u32,
64}
65
66/// Single resource response wrapper
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ResourceResponse<T> {
69    pub data: T,
70}
71
72// ========================================================================================
73// RESOURCE TYPES
74// ========================================================================================
75
76/// Peer resource - represents external systems that send requests to Harmony
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Peer {
79    #[serde(rename = "type")]
80    pub resource_type: String,
81    #[serde(default)]
82    pub id: Option<String>,
83    pub code: String,
84    pub name: String,
85    pub team_id: String,
86    pub gateway_id: Option<String>,
87    #[serde(default)]
88    pub connection: Option<ConnectionConfig>,
89    /// Protocol type - the type of protocol used by this peer (http, https, dicom, etc.)
90    #[serde(default)]
91    pub protocol: Option<String>,
92    #[serde(default)]
93    pub description: Option<String>,
94    #[serde(default)]
95    pub enabled: Option<bool>,
96    #[serde(default)]
97    pub authentication: Option<AuthenticationConfig>,
98    #[serde(default)]
99    pub tags: Option<Vec<String>>,
100    #[serde(default)]
101    pub timeout_secs: Option<u32>,
102    #[serde(default)]
103    pub max_retries: Option<u32>,
104    #[serde(default)]
105    pub created_at: Option<String>,
106    #[serde(default)]
107    pub updated_at: Option<String>,
108}
109
110/// Target resource - represents external systems that receive requests from Harmony
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct Target {
113    #[serde(rename = "type")]
114    pub resource_type: String,
115    #[serde(default)]
116    pub id: Option<String>,
117    pub code: String,
118    pub name: String,
119    pub team_id: String,
120    pub gateway_id: Option<String>,
121    #[serde(default)]
122    pub connection: Option<ConnectionConfig>,
123    /// Protocol type - the type of protocol used by this target (http, https, dicom, etc.)
124    #[serde(default)]
125    pub protocol: Option<String>,
126    #[serde(default)]
127    pub description: Option<String>,
128    #[serde(default)]
129    pub enabled: Option<bool>,
130    #[serde(default)]
131    pub authentication: Option<AuthenticationConfig>,
132    #[serde(default)]
133    pub tags: Option<Vec<String>>,
134    #[serde(default)]
135    pub timeout_secs: Option<u32>,
136    #[serde(default)]
137    pub max_retries: Option<u32>,
138    #[serde(default)]
139    pub created_at: Option<String>,
140    #[serde(default)]
141    pub updated_at: Option<String>,
142}
143
144/// Gateway resource
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct Gateway {
147    #[serde(rename = "type")]
148    pub resource_type: String,
149    #[serde(default)]
150    pub id: Option<String>,
151    pub code: String,
152    pub name: String,
153    pub team_id: String,
154    pub enabled: Option<bool>,
155    #[serde(default)]
156    pub pipelines_path: Option<String>,
157    #[serde(default)]
158    pub transforms_path: Option<String>,
159    #[serde(default)]
160    pub jwks_cache_duration_hours: Option<u32>,
161    #[serde(default)]
162    pub management_enabled: Option<bool>,
163    #[serde(default)]
164    pub management_base_path: Option<String>,
165    #[serde(default)]
166    pub management_network_id: Option<String>,
167    #[serde(default)]
168    pub dns: Option<Vec<String>>,
169    #[serde(default)]
170    pub settings: Option<serde_json::Value>,
171    #[serde(default)]
172    pub created_at: Option<String>,
173    #[serde(default)]
174    pub updated_at: Option<String>,
175}
176
177/// User who authorized a gateway
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct AuthorizedByInfo {
180    pub id: String,
181    pub name: String,
182    pub email: String,
183}
184
185/// Service resource
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct Service {
188    #[serde(rename = "type")]
189    pub resource_type: String,
190    #[serde(default)]
191    pub id: Option<String>,
192    pub code: String,
193    pub name: String,
194    pub team_id: String,
195    pub gateway_id: String,
196    #[serde(default)]
197    pub description: Option<String>,
198    #[serde(default)]
199    pub created_at: Option<String>,
200    #[serde(default)]
201    pub updated_at: Option<String>,
202}
203
204/// Endpoint resource
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct Endpoint {
207    #[serde(rename = "type")]
208    pub resource_type: String,
209    #[serde(default)]
210    pub id: Option<String>,
211    pub code: String,
212    pub name: String,
213    pub team_id: String,
214    pub gateway_id: Option<String>,
215    #[serde(default)]
216    pub service_id: Option<String>,
217    /// Reference to a peer defined in main config (inherits peer's connection settings)
218    #[serde(default)]
219    pub peer_ref: Option<String>,
220    /// Connection configuration (overrides peer_ref settings if both specified)
221    #[serde(default)]
222    pub connection: Option<ConnectionConfig>,
223    /// Authentication configuration (overrides peer_ref settings if both specified)
224    #[serde(default)]
225    pub authentication: Option<AuthenticationConfig>,
226    #[serde(default)]
227    pub path: Option<String>,
228    #[serde(default)]
229    pub methods: Option<Vec<String>>,
230    #[serde(default)]
231    pub description: Option<String>,
232    /// Service-specific options (highest precedence)
233    #[serde(default)]
234    pub options: Option<serde_json::Value>,
235    #[serde(default)]
236    pub created_at: Option<String>,
237    #[serde(default)]
238    pub updated_at: Option<String>,
239}
240
241/// Backend resource
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct Backend {
244    #[serde(rename = "type")]
245    pub resource_type: String,
246    #[serde(default)]
247    pub id: Option<String>,
248    pub code: String,
249    pub name: String,
250    pub team_id: String,
251    pub gateway_id: Option<String>,
252    #[serde(default)]
253    pub service_id: Option<String>,
254    /// Reference to a target defined in main config (inherits target's connection settings)
255    #[serde(default)]
256    pub target_ref: Option<String>,
257    /// Connection configuration (overrides target_ref settings if both specified)
258    #[serde(default)]
259    pub connection: Option<ConnectionConfig>,
260    /// Authentication configuration (overrides target_ref settings if both specified)
261    #[serde(default)]
262    pub authentication: Option<AuthenticationConfig>,
263    #[serde(default)]
264    pub url: Option<String>,
265    #[serde(default)]
266    pub timeout_seconds: Option<u32>,
267    /// Maximum retry attempts (overrides target_ref.max_retries)
268    #[serde(default)]
269    pub max_retries: Option<u32>,
270    /// Service-specific options (highest precedence)
271    #[serde(default)]
272    pub options: Option<serde_json::Value>,
273    #[serde(default)]
274    pub created_at: Option<String>,
275    #[serde(default)]
276    pub updated_at: Option<String>,
277}
278
279/// Pipeline resource
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct Pipeline {
282    #[serde(rename = "type")]
283    pub resource_type: String,
284    #[serde(default)]
285    pub id: Option<String>,
286    pub code: String,
287    pub name: String,
288    pub description: String,
289    pub team_id: String,
290    pub gateway_id: Option<String>,
291    #[serde(default)]
292    pub networks: Option<Vec<String>>,
293    #[serde(default)]
294    pub endpoints: Option<serde_json::Value>,
295    #[serde(default)]
296    pub backends: Option<serde_json::Value>,
297    #[serde(default)]
298    pub middleware: Option<serde_json::Value>,
299    #[serde(default)]
300    pub created_at: Option<String>,
301    #[serde(default)]
302    pub updated_at: Option<String>,
303}
304
305/// Middleware resource  
306#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct Middleware {
308    #[serde(rename = "type")]
309    pub resource_type: String,
310    #[serde(default)]
311    pub id: Option<String>,
312    pub code: String,
313    pub name: String,
314    pub team_id: String,
315    pub middleware_type: String,
316    #[serde(default)]
317    pub options: Option<serde_json::Value>,
318    #[serde(default)]
319    pub created_at: Option<String>,
320    #[serde(default)]
321    pub updated_at: Option<String>,
322}
323
324/// Transform resource
325#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct Transform {
327    #[serde(rename = "type")]
328    pub resource_type: String,
329    #[serde(default)]
330    pub id: Option<String>,
331    pub code: String,
332    pub name: String,
333    pub team_id: String,
334    pub gateway_id: String,
335    #[serde(default)]
336    pub options: Option<TransformOptions>,
337    #[serde(default)]
338    pub created_at: Option<String>,
339    #[serde(default)]
340    pub updated_at: Option<String>,
341}
342
343/// Transform options
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct TransformOptions {
346    pub instructions: Option<String>,
347}
348
349/// Array of rule IDs for a policy.
350///
351/// In harmony-dsl v1.7.0+, policies reference rules by ID using a simple array of strings.
352/// Each ID in this array corresponds to a top-level `[rules.*]` table definition.
353///
354/// # Example
355///
356/// ```json
357/// ["rate_limit_rule_1", "rate_limit_rule_2", "allow_internal"]
358/// ```
359#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
360pub struct PolicyRules(pub Vec<String>);
361
362impl PolicyRules {
363    /// Create a new PolicyRules from a vector of rule IDs
364    pub fn new(rules: Vec<String>) -> Self {
365        PolicyRules(rules)
366    }
367
368    /// Get a reference to the underlying rule IDs
369    pub fn rules(&self) -> &[String] {
370        &self.0
371    }
372
373    /// Convert into the underlying vector of rule IDs
374    pub fn into_inner(self) -> Vec<String> {
375        self.0
376    }
377}
378
379/// Rule resource
380///
381/// Represents a rule definition that can be referenced by policies.
382/// Rules define access control logic with configurable options.
383#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct Rule {
385    #[serde(rename = "type")]
386    pub resource_type: String,
387    pub id: String,
388    pub code: String,
389    #[serde(default)]
390    pub name: Option<String>,
391    pub rule_type: String,
392    pub team_id: String,
393    pub gateway_id: String,
394    #[serde(default)]
395    pub weight: Option<u32>,
396    #[serde(default)]
397    pub enabled: Option<bool>,
398    #[serde(default)]
399    pub options: Option<serde_json::Value>,
400    #[serde(default)]
401    pub created_at: Option<String>,
402    #[serde(default)]
403    pub updated_at: Option<String>,
404}
405
406/// Policy resource
407///
408/// Represents a policy that contains references to rules.
409/// In v1.7.0+, rules are defined as top-level resources and referenced by ID.
410///
411/// # Example (v1.7.0 format)
412///
413/// ```json
414/// {
415///   "type": "policy",
416///   "id": "policy-123",
417///   "code": "rate-limit",
418///   "name": "Rate Limiting Policy",
419///   "enabled": 1,
420///   "team_id": "team-456",
421///   "gateway_id": "gateway-789",
422///   "rules": ["rate_limit_rule_1", "rate_limit_rule_2"],
423///   "created_at": "2024-01-01T00:00:00Z",
424///   "updated_at": "2024-01-01T00:00:00Z"
425/// }
426/// ```
427///
428/// # Breaking Change (v1.6.0 → v1.7.0)
429///
430/// In v1.7.0, the `rules` field format changed from nested objects to an array of rule ID strings.
431/// This aligns with the new flat/reusable policies and rules structure in harmony-dsl.
432#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct Policy {
434    #[serde(rename = "type")]
435    pub resource_type: String,
436    #[serde(default)]
437    pub id: Option<String>,
438    pub code: String,
439    pub name: String,
440    pub enabled: u32,
441    pub team_id: String,
442    pub gateway_id: String,
443    /// Array of rule IDs referenced by this policy.
444    ///
445    /// In v1.7.0+, rules are defined as top-level `[rules.*]` tables and referenced by ID.
446    /// Each ID in this array should correspond to a rule defined at the top level.
447    /// Rules are represented as a typed array of string IDs for better type safety.
448    #[serde(default)]
449    pub rules: Option<PolicyRules>,
450    #[serde(default)]
451    pub created_at: Option<String>,
452    #[serde(default)]
453    pub updated_at: Option<String>,
454}
455
456/// Network resource
457#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct Network {
459    #[serde(rename = "type")]
460    pub resource_type: String,
461    #[serde(default)]
462    pub id: Option<String>,
463    pub code: String,
464    pub name: String,
465    pub team_id: String,
466    pub gateway_id: Option<String>,
467    pub enable_wireguard: bool,
468    #[serde(default)]
469    pub interface: Option<String>,
470    #[serde(default, alias = "http")]
471    pub tcp_config: Option<TcpConfig>,
472    #[serde(default)]
473    pub created_at: Option<String>,
474    #[serde(default)]
475    pub updated_at: Option<String>,
476}
477
478/// TCP configuration for network - used by all protocol adapters (HTTP, DIMSE, etc.)
479#[derive(Debug, Clone, Serialize, Deserialize)]
480pub struct TcpConfig {
481    pub bind_address: Option<String>,
482    pub bind_port: Option<u16>,
483}
484
485/// Runbeam Cloud integration configuration
486#[derive(Debug, Clone, Serialize, Deserialize)]
487pub struct Runbeam {
488    #[serde(rename = "type")]
489    pub resource_type: String,
490    #[serde(default)]
491    pub id: Option<String>,
492    pub code: String,
493    pub name: String,
494    pub team_id: String,
495    pub gateway_id: Option<String>,
496    #[serde(default)]
497    pub enabled: Option<bool>,
498    #[serde(default)]
499    pub cloud_api_base_url: Option<String>,
500    #[serde(default)]
501    pub poll_interval_secs: Option<u32>,
502    #[serde(default)]
503    pub created_at: Option<String>,
504    #[serde(default)]
505    pub updated_at: Option<String>,
506}
507
508/// Authentication resource
509#[derive(Debug, Clone, Serialize, Deserialize)]
510pub struct Authentication {
511    #[serde(rename = "type")]
512    pub resource_type: String,
513    #[serde(default)]
514    pub id: Option<String>,
515    pub code: Option<String>,
516    pub name: String,
517    pub team_id: Option<String>,
518    pub gateway_id: Option<String>,
519    #[serde(default)]
520    pub options: Option<String>,
521    #[serde(default)]
522    pub created_at: Option<String>,
523    #[serde(default)]
524    pub updated_at: Option<String>,
525}
526
527/// Full gateway configuration (for downloading complete config)
528#[derive(Debug, Clone, Serialize, Deserialize)]
529pub struct GatewayConfiguration {
530    pub gateway: Gateway,
531    #[serde(default)]
532    pub peers: Vec<Peer>,
533    #[serde(default)]
534    pub targets: Vec<Target>,
535    #[serde(default)]
536    pub services: Vec<Service>,
537    #[serde(default)]
538    pub endpoints: Vec<Endpoint>,
539    #[serde(default)]
540    pub backends: Vec<Backend>,
541    #[serde(default)]
542    pub pipelines: Vec<Pipeline>,
543    #[serde(default)]
544    pub middlewares: Vec<Middleware>,
545    #[serde(default)]
546    pub transforms: Vec<Transform>,
547    #[serde(default)]
548    pub policies: Vec<Policy>,
549    #[serde(default)]
550    pub rules: Vec<Rule>,
551    #[serde(default)]
552    pub networks: Vec<Network>,
553    #[serde(default)]
554    pub runbeam: Option<Runbeam>,
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;