bucketwarden_browser_ui_preferences/
lib.rs1use serde::{Deserialize, Serialize};
2
3pub const CRATE_PURPOSE: &str = "browser ui preferences contracts";
4pub const PREFERENCES_BOUNDARY_ID: &str = "bnd:bucketwarden.browser-ui.preferences-slice";
5
6#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
7pub struct BrowserUiPreferenceFeature {
8 pub feature_id: String,
9 pub title: String,
10 pub runtime_surface: String,
11 pub api_endpoint: String,
12}
13
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
15pub struct BrowserUiPreferencesContract {
16 pub boundary_id: String,
17 pub implementation_status: String,
18 pub features: Vec<BrowserUiPreferenceFeature>,
19 pub preference_keys: Vec<String>,
20 pub persistence_controls: Vec<String>,
21 pub validation_rules: Vec<String>,
22 pub failure_states: Vec<String>,
23}
24
25pub fn browser_ui_preferences_contract() -> BrowserUiPreferencesContract {
26 BrowserUiPreferencesContract {
27 boundary_id: PREFERENCES_BOUNDARY_ID.to_string(),
28 implementation_status: "implemented".to_string(),
29 features: browser_ui_preference_features(),
30 preference_keys: browser_ui_preference_keys(),
31 persistence_controls: browser_ui_preference_persistence_controls(),
32 validation_rules: browser_ui_preference_validation_rules(),
33 failure_states: browser_ui_preference_failure_states(),
34 }
35}
36
37pub fn browser_ui_preference_features() -> Vec<BrowserUiPreferenceFeature> {
38 [
39 (
40 "feat:bucketwarden.ui.browser.preferences-view",
41 "Browser UI preferences view",
42 "browser-ui.preferences.view",
43 "/ui/api/preferences",
44 ),
45 (
46 "feat:bucketwarden.ui.browser.preferences-persistence",
47 "Browser UI preferences persistence",
48 "browser-ui.preferences.persistence",
49 "/ui/api/preferences",
50 ),
51 ]
52 .into_iter()
53 .map(
54 |(feature_id, title, runtime_surface, api_endpoint)| BrowserUiPreferenceFeature {
55 feature_id: feature_id.to_string(),
56 title: title.to_string(),
57 runtime_surface: runtime_surface.to_string(),
58 api_endpoint: api_endpoint.to_string(),
59 },
60 )
61 .collect()
62}
63
64pub fn browser_ui_preference_keys() -> Vec<String> {
65 [
66 "bucketwarden.ui.density",
67 "bucketwarden.ui.refreshSeconds",
68 "bucketwarden.ui.visibleColumns",
69 "bucketwarden.ui.reportFilters",
70 ]
71 .into_iter()
72 .map(str::to_string)
73 .collect()
74}
75
76pub fn browser_ui_preference_persistence_controls() -> Vec<String> {
77 [
78 "authenticated preferences read",
79 "authenticated preferences write",
80 "runtime snapshot restore",
81 "principal-scoped preference map",
82 "audit event on write",
83 ]
84 .into_iter()
85 .map(str::to_string)
86 .collect()
87}
88
89pub fn browser_ui_preference_validation_rules() -> Vec<String> {
90 [
91 "maximum 64 preference keys",
92 "non-empty key",
93 "key length <= 128",
94 "value length <= 4096",
95 "ASCII alphanumeric dot dash underscore keys",
96 ]
97 .into_iter()
98 .map(str::to_string)
99 .collect()
100}
101
102pub fn browser_ui_preference_failure_states() -> Vec<String> {
103 [
104 "unauthenticated preferences request",
105 "invalid preference key",
106 "oversized preference value",
107 "too many preference keys",
108 "preferences save failure",
109 ]
110 .into_iter()
111 .map(str::to_string)
112 .collect()
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn preferences_contract_tracks_all_slice_features() {
121 let contract = browser_ui_preferences_contract();
122 let feature_ids = contract
123 .features
124 .iter()
125 .map(|feature| feature.feature_id.as_str())
126 .collect::<Vec<_>>();
127
128 assert_eq!(contract.boundary_id, PREFERENCES_BOUNDARY_ID);
129 assert_eq!(contract.implementation_status, "implemented");
130 assert!(feature_ids.contains(&"feat:bucketwarden.ui.browser.preferences-view"));
131 assert!(feature_ids.contains(&"feat:bucketwarden.ui.browser.preferences-persistence"));
132 }
133
134 #[test]
135 fn preferences_contract_requires_persistence_and_validation() {
136 let contract = browser_ui_preferences_contract();
137
138 assert!(contract
139 .preference_keys
140 .contains(&"bucketwarden.ui.refreshSeconds".to_string()));
141 assert!(contract
142 .persistence_controls
143 .contains(&"runtime snapshot restore".to_string()));
144 assert!(contract
145 .validation_rules
146 .contains(&"ASCII alphanumeric dot dash underscore keys".to_string()));
147 assert!(contract
148 .failure_states
149 .contains(&"unauthenticated preferences request".to_string()));
150 }
151}