spin_manifest/schema/
v1.rs1use serde::Deserialize;
2
3use spin_serde::FixedStringVersion;
4
5pub use super::common::{
6    ComponentBuildConfig as ComponentBuildConfigV1, ComponentSource as ComponentSourceV1,
7    Variable as VariableV1, WasiFilesMount as WasiFilesMountV1,
8};
9
10type Map<K, V> = indexmap::IndexMap<K, V>;
11
12#[derive(Deserialize)]
14#[serde(deny_unknown_fields)]
15pub struct AppManifestV1 {
16    #[serde(alias = "spin_version")]
18    #[allow(dead_code)]
19    spin_manifest_version: FixedStringVersion<1>,
20    pub name: String,
22    #[serde(default)]
24    pub version: String,
25    #[serde(default)]
27    pub description: String,
28    #[serde(default)]
30    pub authors: Vec<String>,
31    pub trigger: AppTriggerV1,
33    #[serde(default)]
35    pub variables: Map<String, VariableV1>,
36    #[serde(rename = "component")]
38    #[serde(default)]
39    pub components: Vec<ComponentV1>,
40}
41
42#[derive(Deserialize)]
44pub struct AppTriggerV1 {
45    #[serde(rename = "type")]
47    pub trigger_type: String,
48    #[serde(flatten)]
50    pub config: toml::Table,
51}
52
53#[derive(Deserialize)]
55#[serde(deny_unknown_fields)]
56pub struct ComponentV1 {
57    pub id: String,
59    pub source: ComponentSourceV1,
61    pub trigger: toml::Table,
63    #[serde(default)]
65    pub description: String,
66    #[serde(default)]
68    pub config: Map<String, String>,
69    #[serde(default)]
71    pub environment: Map<String, String>,
72    #[serde(default)]
74    pub files: Vec<WasiFilesMountV1>,
75    #[serde(default)]
77    pub exclude_files: Vec<String>,
78    #[serde(default)]
80    pub allowed_http_hosts: Vec<String>,
81    #[serde(default)]
83    pub allowed_outbound_hosts: Option<Vec<String>>,
84    #[serde(default)]
86    pub key_value_stores: Vec<String>,
87    #[serde(default)]
89    pub sqlite_databases: Vec<String>,
90    #[serde(default)]
92    pub ai_models: Vec<String>,
93    #[serde(default)]
95    pub build: Option<ComponentBuildConfigV1>,
96}
97
98#[cfg(test)]
99mod tests {
100    use toml::toml;
101
102    use super::*;
103
104    #[derive(Deserialize)]
105    #[allow(dead_code)]
106    struct FakeGlobalTriggerConfig {
107        global_option: bool,
108    }
109
110    #[derive(Deserialize)]
111    #[allow(dead_code)]
112    struct FakeTriggerConfig {
113        option: Option<bool>,
114    }
115
116    #[test]
117    fn deserializing_trigger_configs() {
118        let manifest = AppManifestV1::deserialize(toml! {
119            spin_manifest_version = "1"
120            name = "trigger-configs"
121            trigger = { type = "fake", global_option = true }
122            [[component]]
123            id = "my-component"
124            source = "example.wasm"
125            [component.trigger]
126            option = true
127        })
128        .unwrap();
129
130        FakeGlobalTriggerConfig::deserialize(manifest.trigger.config).unwrap();
131
132        FakeTriggerConfig::deserialize(manifest.components[0].trigger.clone()).unwrap();
133    }
134}