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}