Skip to main content

coil_core/manifest/
module.rs

1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct ModuleManifest {
5    pub name: String,
6    pub required_capabilities: Vec<Capability>,
7    pub optional_capabilities: Vec<Capability>,
8    pub config_namespace: Option<String>,
9    pub capability_contracts: Vec<CapabilityContract>,
10    pub module_dependencies: Vec<ModuleDependency>,
11    pub core_service_dependencies: Vec<CoreServiceDependency>,
12    pub migrations: Vec<MigrationContract>,
13    pub route_surfaces: Vec<RouteSurface>,
14    pub jobs: Vec<JobContract>,
15    pub event_subscriptions: Vec<EventSubscription>,
16    pub integration_points: Vec<IntegrationPoint>,
17    pub behaviors: Vec<ModuleBehavior>,
18    pub extension_slots: Vec<ExtensionSlotDescriptor>,
19    pub admin_resources: Vec<AdminResourceContribution>,
20    pub http_surfaces: Vec<HttpSurfaceContribution>,
21    pub data_repositories: Vec<DataRepositoryContribution>,
22    pub search_contributions: Vec<SearchIndexContribution>,
23    pub report_definitions: Vec<ReportDefinition>,
24    pub bulk_operations: Vec<BulkOperationDefinition>,
25}
26
27impl ModuleManifest {
28    pub fn new(name: impl Into<String>) -> Self {
29        Self {
30            name: name.into(),
31            required_capabilities: Vec::new(),
32            optional_capabilities: Vec::new(),
33            config_namespace: None,
34            capability_contracts: Vec::new(),
35            module_dependencies: Vec::new(),
36            core_service_dependencies: Vec::new(),
37            migrations: Vec::new(),
38            route_surfaces: Vec::new(),
39            jobs: Vec::new(),
40            event_subscriptions: Vec::new(),
41            integration_points: Vec::new(),
42            behaviors: Vec::new(),
43            extension_slots: Vec::new(),
44            admin_resources: Vec::new(),
45            http_surfaces: Vec::new(),
46            data_repositories: Vec::new(),
47            search_contributions: Vec::new(),
48            report_definitions: Vec::new(),
49            bulk_operations: Vec::new(),
50        }
51    }
52
53    pub fn with_required_capabilities(mut self, capabilities: Vec<Capability>) -> Self {
54        self.required_capabilities = capabilities;
55        self
56    }
57
58    pub fn with_optional_capabilities(mut self, capabilities: Vec<Capability>) -> Self {
59        self.optional_capabilities = capabilities;
60        self
61    }
62
63    pub fn with_config_namespace(mut self, config_namespace: impl Into<String>) -> Self {
64        self.config_namespace = Some(config_namespace.into());
65        self
66    }
67
68    pub fn with_capability_contracts(mut self, contracts: Vec<CapabilityContract>) -> Self {
69        self.capability_contracts = contracts;
70        self
71    }
72
73    pub fn with_module_dependencies(mut self, dependencies: Vec<ModuleDependency>) -> Self {
74        self.module_dependencies = dependencies;
75        self
76    }
77
78    pub fn with_core_service_dependencies(
79        mut self,
80        dependencies: Vec<CoreServiceDependency>,
81    ) -> Self {
82        self.core_service_dependencies = dependencies;
83        self
84    }
85
86    pub fn with_migrations(mut self, migrations: Vec<MigrationContract>) -> Self {
87        self.migrations = migrations;
88        self
89    }
90
91    pub fn with_route_surfaces(mut self, routes: Vec<RouteSurface>) -> Self {
92        self.route_surfaces = routes;
93        self
94    }
95
96    pub fn with_jobs(mut self, jobs: Vec<JobContract>) -> Self {
97        self.jobs = jobs;
98        self
99    }
100
101    pub fn with_event_subscriptions(mut self, subscriptions: Vec<EventSubscription>) -> Self {
102        self.event_subscriptions = subscriptions;
103        self
104    }
105
106    pub fn with_integration_points(mut self, integrations: Vec<IntegrationPoint>) -> Self {
107        self.integration_points = integrations;
108        self
109    }
110
111    pub fn with_behaviors(mut self, behaviors: Vec<ModuleBehavior>) -> Self {
112        self.behaviors = behaviors;
113        self
114    }
115
116    pub fn with_extension_slots(mut self, extension_slots: Vec<ExtensionSlotDescriptor>) -> Self {
117        self.extension_slots = extension_slots;
118        self
119    }
120
121    pub fn with_admin_resources(mut self, admin_resources: Vec<AdminResourceContribution>) -> Self {
122        self.admin_resources = admin_resources;
123        self
124    }
125
126    pub fn with_http_surfaces(mut self, http_surfaces: Vec<HttpSurfaceContribution>) -> Self {
127        self.http_surfaces = http_surfaces;
128        self
129    }
130
131    pub fn with_data_repositories(
132        mut self,
133        data_repositories: Vec<DataRepositoryContribution>,
134    ) -> Self {
135        self.data_repositories = data_repositories;
136        self
137    }
138
139    pub fn with_search_contributions(
140        mut self,
141        search_contributions: Vec<SearchIndexContribution>,
142    ) -> Self {
143        self.search_contributions = search_contributions;
144        self
145    }
146
147    pub fn with_report_definitions(mut self, report_definitions: Vec<ReportDefinition>) -> Self {
148        self.report_definitions = report_definitions;
149        self
150    }
151
152    pub fn with_bulk_operations(mut self, bulk_operations: Vec<BulkOperationDefinition>) -> Self {
153        self.bulk_operations = bulk_operations;
154        self
155    }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct CapabilityContract {
160    pub capability: Capability,
161    pub required: bool,
162    pub resource_kinds: Vec<String>,
163}
164
165impl CapabilityContract {
166    pub fn required(
167        capability: Capability,
168        resource_kinds: impl IntoIterator<Item = impl Into<String>>,
169    ) -> Self {
170        Self::new(capability, true, resource_kinds)
171    }
172
173    pub fn optional(
174        capability: Capability,
175        resource_kinds: impl IntoIterator<Item = impl Into<String>>,
176    ) -> Self {
177        Self::new(capability, false, resource_kinds)
178    }
179
180    fn new(
181        capability: Capability,
182        required: bool,
183        resource_kinds: impl IntoIterator<Item = impl Into<String>>,
184    ) -> Self {
185        Self {
186            capability,
187            required,
188            resource_kinds: resource_kinds.into_iter().map(Into::into).collect(),
189        }
190    }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194pub enum ModuleDependencyKind {
195    Required,
196    Optional,
197}
198
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct ModuleDependency {
201    pub module: String,
202    pub kind: ModuleDependencyKind,
203    pub reason: String,
204}
205
206impl ModuleDependency {
207    pub fn required(module: impl Into<String>, reason: impl Into<String>) -> Self {
208        Self {
209            module: module.into(),
210            kind: ModuleDependencyKind::Required,
211            reason: reason.into(),
212        }
213    }
214
215    pub fn optional(module: impl Into<String>, reason: impl Into<String>) -> Self {
216        Self {
217            module: module.into(),
218            kind: ModuleDependencyKind::Optional,
219            reason: reason.into(),
220        }
221    }
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq)]
225pub enum CoreServiceDependency {
226    Auth,
227    Data,
228    Cache,
229    Jobs,
230    Storage,
231    Assets,
232    I18n,
233    Seo,
234    A11y,
235    Template,
236    Wasm,
237    Observability,
238    BrowserSecurity,
239    Http,
240    Tls,
241}
242
243impl CoreServiceDependency {
244    pub fn required_service_ids(self) -> &'static [&'static str] {
245        match self {
246            Self::Auth => &["core.auth"],
247            Self::Data => &["core.data", "core.data.migrations"],
248            Self::Cache => &["core.cache.l1", "core.cache.http"],
249            Self::Jobs => &["core.jobs"],
250            Self::Storage => &["core.storage"],
251            Self::Assets => &["core.assets"],
252            Self::I18n => &["core.i18n"],
253            Self::Seo => &["core.seo"],
254            Self::A11y => &["core.a11y"],
255            Self::Template => &["core.template", "core.template.fragments"],
256            Self::Wasm => &["core.wasm", "core.wasm.limits"],
257            Self::Observability => &["core.health", "core.maintenance", "core.flags"],
258            Self::BrowserSecurity => &["core.http.sessions", "core.http.cookies", "core.http.csrf"],
259            Self::Http => &["core.http"],
260            Self::Tls => &["core.tls.reload"],
261        }
262    }
263}
264
265#[derive(Debug, Clone, PartialEq, Eq)]
266pub struct MigrationContract {
267    pub owner: String,
268    pub order: u32,
269    pub description: String,
270}
271
272impl MigrationContract {
273    pub fn new(owner: impl Into<String>, order: u32, description: impl Into<String>) -> Self {
274        Self {
275            owner: owner.into(),
276            order,
277            description: description.into(),
278        }
279    }
280}