runbeam_sdk/runbeam_api/
resources.rs

1use serde::{Deserialize, Serialize};
2
3/// Paginated response wrapper
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct PaginatedResponse<T> {
6    pub data: Vec<T>,
7    #[serde(default)]
8    pub links: Option<PaginationLinks>,
9    #[serde(default)]
10    pub meta: Option<PaginationMeta>,
11}
12
13/// Pagination links
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct PaginationLinks {
16    pub first: Option<String>,
17    pub last: Option<String>,
18    pub prev: Option<String>,
19    pub next: Option<String>,
20}
21
22/// Pagination metadata
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct PaginationMeta {
25    pub current_page: u32,
26    pub from: Option<u32>,
27    pub last_page: u32,
28    #[serde(default)]
29    pub links: Option<Vec<serde_json::Value>>, // Laravel pagination links array
30    pub path: Option<String>,
31    pub per_page: u32,
32    pub to: Option<u32>,
33    pub total: u32,
34}
35
36/// Single resource response wrapper
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct ResourceResponse<T> {
39    pub data: T,
40}
41
42/// Gateway resource
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Gateway {
45    #[serde(rename = "type")]
46    pub resource_type: String,
47    #[serde(default)]
48    pub id: Option<String>,
49    pub code: String,
50    pub name: String,
51    pub team_id: String,
52    pub enabled: Option<bool>,
53    #[serde(default)]
54    pub pipelines_path: Option<String>,
55    #[serde(default)]
56    pub transforms_path: Option<String>,
57    #[serde(default)]
58    pub jwks_cache_duration_hours: Option<u32>,
59    #[serde(default)]
60    pub management_enabled: Option<bool>,
61    #[serde(default)]
62    pub management_base_path: Option<String>,
63    #[serde(default)]
64    pub management_network_id: Option<String>,
65    #[serde(default)]
66    pub dns: Option<Vec<String>>,
67    #[serde(default)]
68    pub settings: Option<serde_json::Value>,
69    #[serde(default)]
70    pub created_at: Option<String>,
71    #[serde(default)]
72    pub updated_at: Option<String>,
73}
74
75/// User who authorized a gateway
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct AuthorizedByInfo {
78    pub id: String,
79    pub name: String,
80    pub email: String,
81}
82
83/// Service resource
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct Service {
86    #[serde(rename = "type")]
87    pub resource_type: String,
88    #[serde(default)]
89    pub id: Option<String>,
90    pub code: String,
91    pub name: String,
92    pub team_id: String,
93    pub gateway_id: String,
94    #[serde(default)]
95    pub description: Option<String>,
96    #[serde(default)]
97    pub created_at: Option<String>,
98    #[serde(default)]
99    pub updated_at: Option<String>,
100}
101
102/// Endpoint resource
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct Endpoint {
105    #[serde(rename = "type")]
106    pub resource_type: String,
107    #[serde(default)]
108    pub id: Option<String>,
109    pub code: String,
110    pub name: String,
111    pub team_id: String,
112    pub gateway_id: Option<String>,
113    #[serde(default)]
114    pub service_id: Option<String>,
115    #[serde(default)]
116    pub path: Option<String>,
117    #[serde(default)]
118    pub methods: Option<Vec<String>>,
119    #[serde(default)]
120    pub description: Option<String>,
121    #[serde(default)]
122    pub created_at: Option<String>,
123    #[serde(default)]
124    pub updated_at: Option<String>,
125}
126
127/// Backend resource
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct Backend {
130    #[serde(rename = "type")]
131    pub resource_type: String,
132    #[serde(default)]
133    pub id: Option<String>,
134    pub code: String,
135    pub name: String,
136    pub team_id: String,
137    pub gateway_id: Option<String>,
138    #[serde(default)]
139    pub service_id: Option<String>,
140    #[serde(default)]
141    pub url: Option<String>,
142    #[serde(default)]
143    pub timeout_seconds: Option<u32>,
144    #[serde(default)]
145    pub created_at: Option<String>,
146    #[serde(default)]
147    pub updated_at: Option<String>,
148}
149
150/// Pipeline resource
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct Pipeline {
153    #[serde(rename = "type")]
154    pub resource_type: String,
155    #[serde(default)]
156    pub id: Option<String>,
157    pub code: String,
158    pub name: String,
159    pub description: String,
160    pub team_id: String,
161    pub gateway_id: Option<String>,
162    #[serde(default)]
163    pub networks: Option<Vec<String>>,
164    #[serde(default)]
165    pub endpoints: Option<serde_json::Value>,
166    #[serde(default)]
167    pub backends: Option<serde_json::Value>,
168    #[serde(default)]
169    pub middleware: Option<serde_json::Value>,
170    #[serde(default)]
171    pub created_at: Option<String>,
172    #[serde(default)]
173    pub updated_at: Option<String>,
174}
175
176/// Middleware resource  
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct Middleware {
179    #[serde(rename = "type")]
180    pub resource_type: String,
181    #[serde(default)]
182    pub id: Option<String>,
183    pub code: String,
184    pub name: String,
185    pub team_id: String,
186    pub middleware_type: String,
187    #[serde(default)]
188    pub options: Option<serde_json::Value>,
189    #[serde(default)]
190    pub created_at: Option<String>,
191    #[serde(default)]
192    pub updated_at: Option<String>,
193}
194
195/// Transform resource
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct Transform {
198    #[serde(rename = "type")]
199    pub resource_type: String,
200    #[serde(default)]
201    pub id: Option<String>,
202    pub code: String,
203    pub name: String,
204    pub team_id: String,
205    pub gateway_id: String,
206    #[serde(default)]
207    pub options: Option<TransformOptions>,
208    #[serde(default)]
209    pub created_at: Option<String>,
210    #[serde(default)]
211    pub updated_at: Option<String>,
212}
213
214/// Transform options
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct TransformOptions {
217    pub instructions: Option<String>,
218}
219
220/// Array of rule IDs for a policy.
221///
222/// In harmony-dsl v1.7.0+, policies reference rules by ID using a simple array of strings.
223/// Each ID in this array corresponds to a top-level `[rules.*]` table definition.
224///
225/// # Example
226///
227/// ```json
228/// ["rate_limit_rule_1", "rate_limit_rule_2", "allow_internal"]
229/// ```
230#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
231pub struct PolicyRules(pub Vec<String>);
232
233impl PolicyRules {
234    /// Create a new PolicyRules from a vector of rule IDs
235    pub fn new(rules: Vec<String>) -> Self {
236        PolicyRules(rules)
237    }
238
239    /// Get a reference to the underlying rule IDs
240    pub fn rules(&self) -> &[String] {
241        &self.0
242    }
243
244    /// Convert into the underlying vector of rule IDs
245    pub fn into_inner(self) -> Vec<String> {
246        self.0
247    }
248}
249
250/// Policy resource
251///
252/// Represents a policy that contains references to rules.
253/// In v1.7.0+, rules are defined as top-level resources and referenced by ID.
254///
255/// # Example (v1.7.0 format)
256///
257/// ```json
258/// {
259///   "type": "policy",
260///   "id": "policy-123",
261///   "code": "rate-limit",
262///   "name": "Rate Limiting Policy",
263///   "enabled": 1,
264///   "team_id": "team-456",
265///   "gateway_id": "gateway-789",
266///   "rules": ["rate_limit_rule_1", "rate_limit_rule_2"],
267///   "created_at": "2024-01-01T00:00:00Z",
268///   "updated_at": "2024-01-01T00:00:00Z"
269/// }
270/// ```
271///
272/// # Breaking Change (v1.6.0 → v1.7.0)
273///
274/// In v1.7.0, the `rules` field format changed from nested objects to an array of rule ID strings.
275/// This aligns with the new flat/reusable policies and rules structure in harmony-dsl.
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct Policy {
278    #[serde(rename = "type")]
279    pub resource_type: String,
280    #[serde(default)]
281    pub id: Option<String>,
282    pub code: String,
283    pub name: String,
284    pub enabled: u32,
285    pub team_id: String,
286    pub gateway_id: String,
287    /// Array of rule IDs referenced by this policy.
288    ///
289    /// In v1.7.0+, rules are defined as top-level `[rules.*]` tables and referenced by ID.
290    /// Each ID in this array should correspond to a rule defined at the top level.
291    /// Rules are represented as a typed array of string IDs for better type safety.
292    #[serde(default)]
293    pub rules: Option<PolicyRules>,
294    #[serde(default)]
295    pub created_at: Option<String>,
296    #[serde(default)]
297    pub updated_at: Option<String>,
298}
299
300/// Network resource
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct Network {
303    #[serde(rename = "type")]
304    pub resource_type: String,
305    #[serde(default)]
306    pub id: Option<String>,
307    pub code: String,
308    pub name: String,
309    pub team_id: String,
310    pub gateway_id: Option<String>,
311    pub enable_wireguard: bool,
312    #[serde(default)]
313    pub interface: Option<String>,
314    #[serde(default, alias = "http")]
315    pub tcp_config: Option<TcpConfig>,
316    #[serde(default)]
317    pub created_at: Option<String>,
318    #[serde(default)]
319    pub updated_at: Option<String>,
320}
321
322/// TCP configuration for network - used by all protocol adapters (HTTP, DIMSE, etc.)
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct TcpConfig {
325    pub bind_address: Option<String>,
326    pub bind_port: Option<u16>,
327}
328
329/// Runbeam Cloud integration configuration
330#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct Runbeam {
332    #[serde(rename = "type")]
333    pub resource_type: String,
334    #[serde(default)]
335    pub id: Option<String>,
336    pub code: String,
337    pub name: String,
338    pub team_id: String,
339    pub gateway_id: Option<String>,
340    #[serde(default)]
341    pub enabled: Option<bool>,
342    #[serde(default)]
343    pub cloud_api_base_url: Option<String>,
344    #[serde(default)]
345    pub poll_interval_secs: Option<u32>,
346    #[serde(default)]
347    pub created_at: Option<String>,
348    #[serde(default)]
349    pub updated_at: Option<String>,
350}
351
352/// Authentication resource
353#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct Authentication {
355    #[serde(rename = "type")]
356    pub resource_type: String,
357    #[serde(default)]
358    pub id: Option<String>,
359    pub code: Option<String>,
360    pub name: String,
361    pub team_id: Option<String>,
362    pub gateway_id: Option<String>,
363    #[serde(default)]
364    pub options: Option<String>,
365    #[serde(default)]
366    pub created_at: Option<String>,
367    #[serde(default)]
368    pub updated_at: Option<String>,
369}
370
371/// Full gateway configuration (for downloading complete config)
372#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct GatewayConfiguration {
374    pub gateway: Gateway,
375    #[serde(default)]
376    pub services: Vec<Service>,
377    #[serde(default)]
378    pub endpoints: Vec<Endpoint>,
379    #[serde(default)]
380    pub backends: Vec<Backend>,
381    #[serde(default)]
382    pub pipelines: Vec<Pipeline>,
383    #[serde(default)]
384    pub middlewares: Vec<Middleware>,
385    #[serde(default)]
386    pub transforms: Vec<Transform>,
387    #[serde(default)]
388    pub policies: Vec<Policy>,
389    #[serde(default)]
390    pub networks: Vec<Network>,
391    #[serde(default)]
392    pub runbeam: Option<Runbeam>,
393}
394
395/// Change resource for configuration change tracking (API v1.0)
396///
397/// This represents a configuration change that needs to be applied to a gateway.
398/// The API returns two different levels of detail:
399///
400/// 1. ChangeMetadata (list view) - returned from `/api/harmony/changes` endpoints
401///    Contains: id, status, type, gateway_id, created_at
402///
403/// 2. ChangeResource (detail view) - returned from `/api/harmony/changes/{change}` endpoint  
404///    Contains all metadata fields plus: pipeline_id, toml_config, metadata, timestamps, error info
405#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct Change {
407    pub id: String,
408    #[serde(default)]
409    pub status: Option<String>,
410    #[serde(rename = "type")]
411    pub resource_type: String,
412    pub gateway_id: String,
413    #[serde(default)]
414    pub pipeline_id: Option<String>,
415    /// TOML configuration content (only present in detail view)
416    #[serde(default)]
417    pub toml_config: Option<String>,
418    /// Additional metadata (only present in detail view)
419    #[serde(default)]
420    pub metadata: Option<serde_json::Value>,
421    pub created_at: String,
422    #[serde(default)]
423    pub acknowledged_at: Option<String>,
424    #[serde(default)]
425    pub applied_at: Option<String>,
426    #[serde(default)]
427    pub failed_at: Option<String>,
428    #[serde(default)]
429    pub error_message: Option<String>,
430    #[serde(default)]
431    pub error_details: Option<serde_json::Value>,
432}
433
434/// Response from the base URL discovery endpoint
435#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct BaseUrlResponse {
437    /// Base URL for the Harmony API (e.g., https://runbeam.lndo.site/api)
438    pub base_url: String,
439    /// Optional path for changes API (e.g., "/")
440    #[serde(default)]
441    pub changes_path: Option<String>,
442    /// Optional fully resolved URL (base_url + changes_path)
443    #[serde(default)]
444    pub full_url: Option<String>,
445}
446
447/// Request payload for acknowledging multiple changes
448#[derive(Debug, Clone, Serialize, Deserialize)]
449pub struct AcknowledgeChangesRequest {
450    pub change_ids: Vec<String>,
451}
452
453/// Request payload for reporting a failed change
454#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct ChangeFailedRequest {
456    pub error: String,
457    #[serde(skip_serializing_if = "Option::is_none")]
458    pub details: Option<Vec<String>>,
459}
460
461/// Response from acknowledging multiple changes
462#[derive(Debug, Clone, Serialize, Deserialize)]
463pub struct AcknowledgeChangesResponse {
464    pub acknowledged: Vec<String>,
465    pub failed: Vec<String>,
466}
467
468/// Response from marking a change as applied or failed
469#[derive(Debug, Clone, Serialize, Deserialize)]
470pub struct ChangeStatusResponse {
471    pub success: bool,
472    pub message: String,
473}
474
475/// Type alias for change applied response
476pub type ChangeAppliedResponse = ChangeStatusResponse;
477
478/// Type alias for change failed response  
479pub type ChangeFailedResponse = ChangeStatusResponse;