1use std::collections::BTreeMap;
2
3use lenso_app_plan::CapabilityOperationKind;
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
8#[serde(deny_unknown_fields)]
9pub struct PluginManifest {
10 pub schema_version: u32,
11 pub plugin_id: String,
12 pub release_version: String,
13 pub artifacts: Vec<ArtifactDeclaration>,
14 pub module_contributions: Vec<ModuleContribution>,
15 #[serde(default)]
16 pub data_contributions: Vec<DataContribution>,
17 #[serde(default)]
18 pub permission_requests: Vec<PermissionRequest>,
19 #[serde(default)]
20 pub features: Vec<PluginFeature>,
21 #[serde(default)]
22 pub binding_templates: Vec<BindingTemplate>,
23 #[serde(default)]
24 pub product_metadata: Vec<ProductMetadataDeclaration>,
25}
26
27#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29#[serde(deny_unknown_fields)]
30pub struct PluginManifestV2 {
31 pub schema_version: u32,
32 pub plugin_id: String,
33 pub release_version: String,
34 pub artifact: PluginArtifactV2,
35 pub entry: PluginEntryV2,
36}
37
38#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
40#[serde(deny_unknown_fields)]
41pub struct PluginArtifactV2 {
42 pub path: String,
43 pub digest: String,
44 pub size: u64,
45 pub media_type: String,
46 pub target: String,
47}
48
49#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
51#[serde(deny_unknown_fields)]
52pub struct PluginEntryV2 {
53 pub descriptor: serde_json::Value,
54}
55
56#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
58#[serde(deny_unknown_fields)]
59pub struct PluginFeature {
60 pub id: String,
61 #[serde(default)]
62 pub module_contribution_ids: Vec<String>,
63 #[serde(default)]
64 pub data_contribution_ids: Vec<String>,
65 #[serde(default)]
66 pub artifact_ids: Vec<String>,
67 #[serde(default)]
68 pub permission_request_ids: Vec<String>,
69 #[serde(default)]
70 pub product_metadata_ids: Vec<String>,
71}
72
73#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
75#[serde(deny_unknown_fields)]
76pub struct BindingTemplate {
77 pub consumer_contribution_id: String,
78 pub provider_contribution_id: String,
79 pub capability_id: String,
80}
81
82#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
84#[serde(deny_unknown_fields)]
85pub struct ProductMetadataDeclaration {
86 pub id: String,
87 pub namespace: String,
88 pub schema_id: String,
89 pub path: String,
90 pub digest: String,
91}
92
93#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
95#[serde(deny_unknown_fields)]
96pub struct ArtifactDeclaration {
97 pub id: String,
98 pub kind: ArtifactKind,
99 pub digest: String,
100 pub size: u64,
101 pub media_type: String,
102 pub path: String,
103 pub targets: Vec<String>,
104}
105
106#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
108#[serde(rename_all = "snake_case")]
109pub enum ArtifactKind {
110 Process,
111 WasmComponent,
112 QuickJsModule,
113 NativeDylib,
114 Data,
115}
116
117#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
119#[serde(deny_unknown_fields)]
120pub struct ModuleContribution {
121 pub id: String,
122 pub package_id: String,
123 pub configuration_schema_digest: String,
124 pub provides: Vec<CapabilityDeclaration>,
125 #[serde(default)]
126 pub requires: Vec<CapabilityRequirement>,
127 pub implementations: Vec<ImplementationVariant>,
128 #[serde(default)]
129 pub permission_request_ids: Vec<String>,
130 #[serde(default)]
131 pub state: Option<StateDeclaration>,
132}
133
134#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
136#[serde(deny_unknown_fields)]
137pub struct StateDeclaration {
138 pub state_schema_id: String,
139 pub state_schema_digest: String,
140}
141
142#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
144#[serde(deny_unknown_fields)]
145pub struct CapabilityDeclaration {
146 pub capability_id: String,
147 pub descriptor_version: String,
148 pub descriptor_digest: String,
149 pub request_operations: Vec<String>,
151 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
153 pub operation_kinds: BTreeMap<String, CapabilityOperationKind>,
154}
155
156#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
158#[serde(deny_unknown_fields)]
159pub struct CapabilityRequirement {
160 pub capability_id: String,
161 pub descriptor_version: String,
162 pub cardinality: RequirementCardinality,
163}
164
165#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
167#[serde(rename_all = "snake_case")]
168pub enum RequirementCardinality {
169 One,
170 Optional,
171 Many,
172}
173
174#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
176#[serde(deny_unknown_fields)]
177pub struct ImplementationVariant {
178 pub id: String,
179 pub artifact: Option<String>,
180 pub built_in_factory: Option<String>,
181 pub entrypoint: String,
182 pub execution_class: String,
183 pub targets: Vec<String>,
184 pub profiles: Vec<String>,
185 pub support_channel: SupportChannel,
186 pub trust: TrustLevel,
187}
188
189#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
191#[serde(rename_all = "snake_case")]
192pub enum SupportChannel {
193 Stable,
194 Preview,
195 Experimental,
196}
197
198#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
200#[serde(rename_all = "snake_case")]
201pub enum TrustLevel {
202 Constrained,
203 Isolated,
204 Trusted,
205}
206
207#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
209#[serde(deny_unknown_fields)]
210pub struct DataContribution {
211 pub id: String,
212 pub artifact: String,
213 pub media_type: String,
214 pub content_schema_id: String,
215 pub content_schema_digest: String,
216 pub product_metadata_digest: String,
217}
218
219#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
221#[serde(deny_unknown_fields)]
222pub struct PermissionRequest {
223 pub id: String,
224 pub resource_kind: String,
225 pub required: bool,
226 pub scope: serde_json::Value,
227 pub explanation_key: String,
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn legacy_request_capability_declaration_remains_canonical() {
236 let bytes = br#"{"capability_id":"example.echo@1","descriptor_version":"1.0.0","descriptor_digest":"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","request_operations":["echo"]}"#;
237 let declaration: CapabilityDeclaration = serde_json::from_slice(bytes).unwrap();
238
239 assert!(declaration.operation_kinds.is_empty());
240 assert_eq!(serde_json::to_vec(&declaration).unwrap(), bytes);
241 }
242}