1use super::contracts::DEFAULT_SCHEMA;
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
5pub struct Redacted(Option<String>);
6
7impl Redacted {
8 pub fn new(value: Option<String>) -> Self {
9 Self(value)
10 }
11
12 pub fn as_deref(&self) -> Option<&str> {
13 self.0.as_deref()
14 }
15
16 pub fn is_some(&self) -> bool {
17 self.0.is_some()
18 }
19
20 pub fn clone_inner(&self) -> Option<String> {
21 self.0.clone()
22 }
23}
24
25impl From<Option<String>> for Redacted {
26 fn from(value: Option<String>) -> Self {
27 Self::new(value)
28 }
29}
30
31impl std::fmt::Debug for Redacted {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self.0 {
34 Some(_) => f.write_str("<redacted>"),
35 None => f.write_str("None"),
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41pub struct StandaloneSetupRequest {
42 pub standalone: bool,
43 #[serde(skip_serializing, default)]
46 pub database_url: Redacted,
47 pub no_services: bool,
48 pub overwrite_code_index: bool,
49 pub schema: String,
50 pub embedding_provider: Option<String>,
51 pub embedding_api_base: Option<String>,
52 pub embedding_model: Option<String>,
53 pub embedding_query_prefix: Option<String>,
54 pub embedding_vector_dim: Option<usize>,
55 #[serde(skip_serializing, default)]
58 pub embedding_api_key: Redacted,
59 pub falkordb_host: Option<String>,
60 pub falkordb_port: Option<u16>,
61 #[serde(skip_serializing, default)]
64 pub falkordb_password: Redacted,
65 pub qdrant_url: Option<String>,
66}
67
68impl StandaloneSetupRequest {
69 pub fn new(standalone: bool, database_url: Option<String>, schema: Option<String>) -> Self {
70 Self {
71 standalone,
72 database_url: Redacted::new(database_url),
73 no_services: false,
74 overwrite_code_index: false,
75 schema: schema.unwrap_or_else(|| DEFAULT_SCHEMA.to_string()),
76 embedding_provider: None,
77 embedding_api_base: None,
78 embedding_model: None,
79 embedding_query_prefix: None,
80 embedding_vector_dim: None,
81 embedding_api_key: Redacted::default(),
82 falkordb_host: None,
83 falkordb_port: None,
84 falkordb_password: Redacted::default(),
85 qdrant_url: None,
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn standalone_setup_request_debug_redacts_secrets() {
96 let mut request = StandaloneSetupRequest::new(
97 true,
98 Some("postgres://user:secret-db@localhost/gobby".to_string()),
99 None,
100 );
101 request.embedding_api_key = Some("secret-embedding-key".to_string()).into();
102 request.falkordb_password = Some("secret-falkor-password".to_string()).into();
103
104 let debug = format!("{request:?}");
105
106 assert!(debug.contains("<redacted>"));
107 assert!(!debug.contains("secret-db"));
108 assert!(!debug.contains("secret-embedding-key"));
109 assert!(!debug.contains("secret-falkor-password"));
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114pub struct StandaloneServicesStatus {
115 pub provisioned: bool,
116 pub compose_file: Option<String>,
117 pub health_checks: Vec<String>,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct StandaloneEmbeddingStatus {
122 pub provider: String,
123 pub api_base: String,
124 pub model: String,
125 pub query_prefix: Option<String>,
126 pub vector_dim: usize,
127 pub api_key_present: bool,
128 pub api_key_fingerprint: Option<String>,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
132pub struct StandaloneFailure {
133 pub name: String,
134 pub reason: String,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct StandaloneSetupStatus {
139 pub namespace: String,
140 pub schema: String,
141 pub created: Vec<String>,
142 pub skipped: Vec<String>,
143 pub failed: Vec<StandaloneFailure>,
144 pub config_file: Option<String>,
145 pub services: Option<StandaloneServicesStatus>,
146 pub embedding: Option<StandaloneEmbeddingStatus>,
147}