Skip to main content

briefcase_node/
simple_models.rs

1//! Simplified Node.js bindings that avoid NAPI-RS generic constraints
2
3use briefcase_core::*;
4use napi::Result;
5use napi_derive::napi;
6
7/// Simple Input wrapper for Node.js
8#[napi]
9pub struct SimpleInput {
10    inner: Input,
11}
12
13#[napi]
14impl SimpleInput {
15    #[napi(constructor)]
16    pub fn new(name: String, value: String, data_type: String) -> Result<Self> {
17        let json_value = serde_json::from_str(&value).unwrap_or(serde_json::Value::String(value));
18
19        Ok(Self {
20            inner: Input::new(name, json_value, data_type),
21        })
22    }
23
24    #[napi(getter)]
25    pub fn name(&self) -> String {
26        self.inner.name.clone()
27    }
28
29    #[napi(getter)]
30    pub fn value(&self) -> String {
31        self.inner.value.to_string()
32    }
33
34    #[napi(getter)]
35    pub fn data_type(&self) -> String {
36        self.inner.data_type.clone()
37    }
38}
39
40/// Simple Output wrapper for Node.js
41#[napi]
42pub struct SimpleOutput {
43    inner: Output,
44}
45
46#[napi]
47impl SimpleOutput {
48    #[napi(constructor)]
49    pub fn new(name: String, value: String, data_type: String) -> Result<Self> {
50        let json_value = serde_json::from_str(&value).unwrap_or(serde_json::Value::String(value));
51
52        Ok(Self {
53            inner: Output::new(name, json_value, data_type),
54        })
55    }
56
57    #[napi]
58    pub fn with_confidence(&mut self, confidence: f64) -> &Self {
59        self.inner = self.inner.clone().with_confidence(confidence);
60        self
61    }
62
63    #[napi(getter)]
64    pub fn name(&self) -> String {
65        self.inner.name.clone()
66    }
67
68    #[napi(getter)]
69    pub fn value(&self) -> String {
70        self.inner.value.to_string()
71    }
72
73    #[napi(getter)]
74    pub fn confidence(&self) -> Option<f64> {
75        self.inner.confidence
76    }
77}
78
79/// Simple Decision Snapshot wrapper
80#[napi]
81pub struct SimpleDecisionSnapshot {
82    inner: DecisionSnapshot,
83}
84
85#[napi]
86impl SimpleDecisionSnapshot {
87    #[napi(constructor)]
88    pub fn new(function_name: String) -> Result<Self> {
89        Ok(Self {
90            inner: DecisionSnapshot::new(function_name),
91        })
92    }
93
94    #[napi]
95    pub fn add_input(&mut self, input: &SimpleInput) -> &Self {
96        self.inner = self.inner.clone().add_input(input.inner.clone());
97        self
98    }
99
100    #[napi]
101    pub fn add_output(&mut self, output: &SimpleOutput) -> &Self {
102        self.inner = self.inner.clone().add_output(output.inner.clone());
103        self
104    }
105
106    #[napi]
107    pub fn with_execution_time(&mut self, time_ms: f64) -> &Self {
108        self.inner = self.inner.clone().with_execution_time(time_ms);
109        self
110    }
111
112    #[napi]
113    pub fn add_tag(&mut self, key: String, value: String) -> &Self {
114        self.inner = self.inner.clone().add_tag(key, value);
115        self
116    }
117
118    #[napi(getter)]
119    pub fn function_name(&self) -> String {
120        self.inner.function_name.clone()
121    }
122
123    #[napi(getter)]
124    pub fn execution_time_ms(&self) -> Option<f64> {
125        self.inner.execution_time_ms
126    }
127
128    #[napi]
129    pub fn to_json(&self) -> Result<String> {
130        serde_json::to_string(&self.inner)
131            .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e)))
132    }
133}
134
135/// Simple Drift Calculator
136#[napi]
137pub struct SimpleDriftCalculator {
138    inner: briefcase_core::DriftCalculator,
139}
140
141#[napi]
142impl SimpleDriftCalculator {
143    #[napi(constructor)]
144    pub fn new() -> Result<Self> {
145        Ok(Self {
146            inner: briefcase_core::DriftCalculator::new(),
147        })
148    }
149
150    #[napi(factory)]
151    pub fn with_threshold(threshold: f64) -> Result<Self> {
152        Ok(Self {
153            inner: briefcase_core::DriftCalculator::with_threshold(threshold),
154        })
155    }
156
157    #[napi]
158    pub fn calculate_drift(&self, outputs: Vec<String>) -> Result<String> {
159        let metrics = self.inner.calculate_drift(&outputs);
160        serde_json::to_string(&serde_json::json!({
161            "consistency_score": metrics.consistency_score,
162            "agreement_rate": metrics.agreement_rate,
163            "drift_score": metrics.drift_score,
164            "consensus_output": metrics.consensus_output,
165            "outliers": metrics.outliers,
166        }))
167        .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e)))
168    }
169
170    #[napi]
171    pub fn get_status_string(&self, outputs: Vec<String>) -> Result<String> {
172        let metrics = self.inner.calculate_drift(&outputs);
173        let status = self.inner.get_status(&metrics);
174        Ok(format!("{:?}", status).to_lowercase())
175    }
176}
177
178/// Simple Cost Calculator
179#[napi]
180pub struct SimpleCostCalculator {
181    inner: briefcase_core::CostCalculator,
182}
183
184#[napi]
185impl SimpleCostCalculator {
186    #[napi(constructor)]
187    pub fn new() -> Result<Self> {
188        Ok(Self {
189            inner: briefcase_core::CostCalculator::new(),
190        })
191    }
192
193    #[napi]
194    pub fn estimate_cost(
195        &self,
196        model: String,
197        input_tokens: u32,
198        output_tokens: u32,
199    ) -> Result<String> {
200        match self
201            .inner
202            .estimate_cost(&model, input_tokens as usize, output_tokens as usize)
203        {
204            Ok(estimate) => serde_json::to_string(&estimate)
205                .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e))),
206            Err(e) => Err(napi::Error::from_reason(format!(
207                "Cost estimation error: {}",
208                e
209            ))),
210        }
211    }
212
213    #[napi]
214    pub fn check_budget(&self, spent: f64, budget: f64) -> Result<String> {
215        let status = self.inner.check_budget(spent, budget);
216        serde_json::to_string(&status)
217            .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e)))
218    }
219
220    #[napi]
221    pub fn project_monthly_cost(
222        &self,
223        model: String,
224        daily_input: u32,
225        daily_output: u32,
226        days: f64,
227    ) -> Result<String> {
228        match self.inner.project_monthly_cost(
229            &model,
230            daily_input as usize,
231            daily_output as usize,
232            days,
233        ) {
234            Ok(projection) => serde_json::to_string(&projection)
235                .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e))),
236            Err(e) => Err(napi::Error::from_reason(format!("Projection error: {}", e))),
237        }
238    }
239}
240
241/// Simple Sanitizer
242#[napi]
243pub struct SimpleSanitizer {
244    inner: briefcase_core::Sanitizer,
245}
246
247#[napi]
248impl SimpleSanitizer {
249    #[napi(constructor)]
250    pub fn new() -> Result<Self> {
251        Ok(Self {
252            inner: briefcase_core::Sanitizer::new(),
253        })
254    }
255
256    #[napi]
257    pub fn sanitize(&self, text: String) -> Result<String> {
258        let result = self.inner.sanitize(&text);
259        serde_json::to_string(&serde_json::json!({
260            "sanitized": result.sanitized,
261            "redactions": result.redactions.len(),
262        }))
263        .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e)))
264    }
265
266    #[napi]
267    pub fn add_pattern(&mut self, name: String, pattern: String) -> Result<()> {
268        self.inner
269            .add_pattern(&name, &pattern)
270            .map_err(|e| napi::Error::from_reason(format!("Pattern error: {}", e)))
271    }
272
273    #[napi]
274    pub fn analyze(&self, text: String) -> Result<String> {
275        let analysis = self.inner.analyze(&text);
276        serde_json::to_string(&serde_json::json!({
277            "has_pii": analysis.has_pii,
278            "total_matches": analysis.total_matches,
279            "unique_types": analysis.unique_types,
280        }))
281        .map_err(|e| napi::Error::from_reason(format!("Serialization error: {}", e)))
282    }
283}