1use serde::{Deserialize, Serialize};
2
3use crate::AeoError;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub enum EntityType {
8 Person,
10 Organization,
12 Product,
14 Place,
16 Concept,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(rename_all = "kebab-case")]
23pub enum VerificationType {
24 Domain,
26 Dns,
28 Github,
30 Linkedin,
32 Gpg,
34 #[serde(rename = "well-known-uri")]
36 WellKnownUri,
37}
38
39#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
41#[serde(rename_all = "lowercase")]
42pub enum Confidence {
43 #[default]
45 High,
46 Medium,
48 Low,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "lowercase")]
55pub enum AuditMode {
56 None,
58 Signature,
60 Endpoint,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(deny_unknown_fields)]
67pub struct Entity {
68 pub id: String,
70 #[serde(rename = "type")]
72 pub entity_type: EntityType,
73 pub name: String,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub aliases: Option<Vec<String>>,
78 pub canonical_url: String,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(deny_unknown_fields)]
85pub struct Verification {
86 #[serde(rename = "type")]
88 pub verification_type: VerificationType,
89 pub value: String,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub proof_uri: Option<String>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(deny_unknown_fields)]
99pub struct Authority {
100 pub primary_sources: Vec<String>,
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub evidence_links: Option<Vec<String>>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub verifications: Option<Vec<Verification>>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(deny_unknown_fields)]
113pub struct Claim {
114 pub id: String,
116 pub predicate: String,
118 pub value: serde_json::Value,
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub evidence: Option<Vec<String>>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub valid_from: Option<String>,
126 #[serde(default, skip_serializing_if = "Option::is_none")]
128 pub valid_until: Option<Option<String>>,
129 #[serde(default)]
131 pub confidence: Confidence,
132}
133
134#[derive(Debug, Clone, Default, Serialize, Deserialize)]
136#[serde(deny_unknown_fields)]
137pub struct CitationPreferences {
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub preferred_attribution: Option<String>,
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub canonical_links: Option<Vec<String>>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub do_not_cite: Option<Vec<String>>,
147}
148
149#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151#[serde(deny_unknown_fields)]
152pub struct AnswerConstraints {
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub must_include: Option<Vec<String>>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub must_not_include: Option<Vec<String>>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub freshness_window_days: Option<u32>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166#[serde(deny_unknown_fields)]
167pub struct Audit {
168 pub mode: AuditMode,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub signing_key_uri: Option<String>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub signature: Option<String>,
176 #[serde(skip_serializing_if = "Option::is_none")]
178 pub endpoint_uri: Option<String>,
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub endpoint_schema: Option<String>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(deny_unknown_fields)]
187pub struct Document {
188 pub aeo_version: String,
190 pub entity: Entity,
192 pub authority: Authority,
194 pub claims: Vec<Claim>,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub citation_preferences: Option<CitationPreferences>,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub answer_constraints: Option<AnswerConstraints>,
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub audit: Option<Audit>,
205}
206
207impl Document {
208 pub fn from_json(raw: &str) -> Result<Self, AeoError> {
210 serde_json::from_str(raw).map_err(AeoError::Parse)
211 }
212
213 pub fn to_json(&self) -> Result<String, AeoError> {
215 serde_json::to_string_pretty(self).map_err(AeoError::Parse)
216 }
217
218 pub fn claim_ids(&self) -> Vec<&str> {
220 self.claims.iter().map(|c| c.id.as_str()).collect()
221 }
222
223 pub fn find_claim(&self, id: &str) -> Option<&Claim> {
225 self.claims.iter().find(|c| c.id == id)
226 }
227}