1use serde::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7
8pub const MANIFEST_VERSION: &str = "1";
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum RouteMode {
14 Static,
15 Ssr,
16 Spa,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(rename_all = "lowercase")]
21pub enum Requires {
22 User,
23 Project,
24 Region,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct CachePolicy {
29 pub ttl: u64,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub swr: Option<u64>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub negative_ttl: Option<u64>,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub vary: Option<Vec<String>>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
39pub struct Hydration {
40 pub script: String,
41 pub code_split: Vec<String>,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(rename_all = "lowercase")]
49pub enum ResolvedPlacement {
50 Host,
51 Edge,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60pub struct RetryPolicy {
61 pub attempts: u32,
63 pub backoff_ms: Vec<u64>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub retry_on: Option<String>,
68 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub budget_ms: Option<u64>,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74pub struct QueuePolicy {
75 pub queue: String,
76 pub ack: String,
77 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub max_delay_ms: Option<u64>,
79}
80
81pub const DEFAULT_RESILIENCE_TIMEOUT_MS: u64 = 30_000;
83
84#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
85pub struct ResiliencePolicy {
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub retry: Option<RetryPolicy>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub queue: Option<QueuePolicy>,
90 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub timeout_ms: Option<u64>,
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108#[serde(untagged)]
109pub enum Prerender {
110 Literal {
111 params: Vec<BTreeMap<String, String>>,
112 },
113 SourceDerived {
114 from: String,
115 query: String,
116 param: String,
117 },
118 FromData {
119 from_data: String,
120 items_key: String,
121 param: String,
122 },
123 Deferred {
124 deferred: bool,
127 },
128}
129
130impl Prerender {
131 pub fn is_deferred(&self) -> bool {
135 matches!(self, Prerender::Deferred { deferred: true })
136 }
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub struct Route {
141 pub route: String,
142 pub mode: RouteMode,
143 pub render_entrypoint: String,
144 #[serde(default, skip_serializing_if = "Option::is_none")]
145 pub requires: Option<Vec<Requires>>,
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub source_reads: Option<Vec<String>>,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
152 pub data_inputs: Option<Vec<String>>,
153 pub cache_policy: CachePolicy,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub concurrency: Option<u32>,
156 #[serde(default, skip_serializing_if = "Option::is_none")]
157 pub hydration: Option<Hydration>,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub prerender: Option<Prerender>,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub placement: Option<ResolvedPlacement>,
163 #[serde(default, skip_serializing_if = "Option::is_none")]
165 pub resilience: Option<ResiliencePolicy>,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
169pub struct StaticAsset {
170 pub key: String,
171 pub content_hash: String,
172 pub content_type: String,
173 pub immutable: bool,
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
177pub struct ErrorRoutes {
178 #[serde(default, skip_serializing_if = "Option::is_none", rename = "404")]
179 pub not_found: Option<String>,
180 #[serde(default, skip_serializing_if = "Option::is_none", rename = "5xx")]
181 pub server_error: Option<String>,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
189pub struct Hook {
190 pub entrypoint: String,
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
196pub struct Manifest {
197 pub version: String,
198 pub build_id: String,
199 pub routes: Vec<Route>,
200 #[serde(default)]
201 pub static_assets: Vec<StaticAsset>,
202 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub error_routes: Option<ErrorRoutes>,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
210 pub hooks: Option<BTreeMap<String, Hook>>,
211 #[serde(default, skip_serializing_if = "Option::is_none")]
216 pub ssr_prefixes: Option<Vec<String>>,
217}