Skip to main content

ordinary_template/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(clippy::all, clippy::pedantic)]
3#![allow(clippy::missing_errors_doc, clippy::cast_sign_loss)]
4
5// Copyright (C) 2026 Ordinary Labs, LLC.
6//
7// SPDX-License-Identifier: AGPL-3.0-only
8
9mod ffi;
10
11use anyhow::bail;
12use bytes::Bytes;
13use flexbuffers::VectorReader;
14use hashbrown::HashMap;
15use http::{HeaderName, HeaderValue, StatusCode};
16use parking_lot::RwLock;
17use std::collections::BTreeMap;
18use std::str::FromStr;
19use std::sync::Arc;
20use std::time::Duration;
21use tracing::{Instrument, info_span, instrument};
22
23use ordinary_auth::Auth;
24use ordinary_config::{
25    ContentDefinition, ModelConfig, OrdinaryConfig, QueryExpression, StoredCachePolicy,
26    TemplateConfig, TemplateFfiVersion, TemplateRef, TemplateRefField, TemplateRefFieldBind,
27};
28use ordinary_storage::{ArtifactKind, CacheRead, RefDepth, Storage};
29use ordinary_types::{Field, Kind};
30
31use wasmtime::Module;
32
33pub use wasmtime::Engine;
34
35#[cfg(feature = "studio")]
36const IFRAME_RESIZER_CHILD_URL: &str = "https://cdn.jsdelivr.net/npm/@iframe-resizer/child@5.5.9";
37
38#[derive(Clone, Debug, PartialEq)]
39pub enum TemplateResult {
40    Result(Bytes),
41    StatusCode(StatusCode),
42}
43
44#[derive(Clone, Debug)]
45enum Include {
46    Field(u8, Kind),
47    Fields(u8, Vec<Include>, bool),
48}
49
50impl Include {
51    fn build_for_field(
52        field: &Field,
53        ref_field: &TemplateRefField,
54        model_map: &HashMap<String, ModelConfig>,
55        ref_depth: &mut RefDepth,
56    ) -> anyhow::Result<Self> {
57        let field_idx = field.idx;
58
59        match &ref_field.fields {
60            Some(nested_ref_fields) => {
61                let mut nested = vec![];
62                let mut is_list = false;
63
64                let mut nested_field_map = HashMap::new();
65
66                match &field.kind {
67                    Kind::List { kind } => {
68                        if let Kind::Object { name: _, fields } = &**kind {
69                            for nested_field in fields {
70                                nested_field_map.insert(nested_field.name.clone(), nested_field);
71                            }
72
73                            is_list = true;
74                        } else {
75                            bail!("cannot have nested fields on non object");
76                        }
77                    }
78                    Kind::Object { name: _, fields } => {
79                        for nested_field in fields {
80                            nested_field_map.insert(nested_field.name.clone(), nested_field);
81                        }
82                    }
83                    Kind::Ref {
84                        model,
85                        field: _,
86                        many: _,
87                    } => {
88                        if let Some(model) = model_map.get(model) {
89                            for nested_field in &model.fields {
90                                nested_field_map.insert(nested_field.name.clone(), nested_field);
91                            }
92
93                            ref_depth.0.push(((field.idx, 1, None), RefDepth(vec![])));
94                        }
95                    }
96                    _ => bail!("cannot have nested fields on non object"),
97                }
98
99                let mut fields_clone = nested_ref_fields.clone();
100                fields_clone.sort_by_key(|a| a.idx);
101
102                for nested_ref_field in fields_clone {
103                    if let Some(nested_field) = nested_field_map.get(&nested_ref_field.name) {
104                        nested.push(Self::build_for_field(
105                            nested_field,
106                            &nested_ref_field,
107                            model_map,
108                            ref_depth,
109                        )?);
110                    }
111                }
112
113                nested.shrink_to_fit();
114                Ok(Include::Fields(field_idx, nested, is_list))
115            }
116            None => Ok(Include::Field(field_idx, field.kind.clone())),
117        }
118    }
119
120    fn build_for_content(
121        content_def: &ContentDefinition,
122        template_ref: &TemplateRef,
123    ) -> anyhow::Result<Vec<Self>> {
124        let mut include_fields = vec![];
125
126        let mut fields_clone = template_ref.fields.clone();
127        fields_clone.sort_by_key(|a| a.idx);
128
129        let mut content_def_field_map = HashMap::new();
130        for field in &content_def.fields {
131            content_def_field_map.insert(field.name.clone(), field);
132        }
133
134        for field in fields_clone {
135            if let Some(def_field) = content_def_field_map.get(&field.name) {
136                let include = Self::build_for_field(
137                    def_field,
138                    &field,
139                    &HashMap::new(),
140                    &mut RefDepth(vec![]),
141                )?;
142                include_fields.push(include);
143            }
144        }
145
146        include_fields.shrink_to_fit();
147        Ok(include_fields)
148    }
149
150    fn build_for_model(
151        model_config: &ModelConfig,
152        template_ref: &TemplateRef,
153        model_map: &HashMap<String, ModelConfig>,
154    ) -> anyhow::Result<(Vec<Self>, RefDepth)> {
155        let mut include_fields = vec![];
156
157        let mut fields_clone = template_ref.fields.clone();
158        fields_clone.sort_by_key(|a| a.idx);
159
160        let mut model_config_field_map = HashMap::new();
161        for field in &model_config.fields {
162            model_config_field_map.insert(field.name.clone(), field);
163        }
164        let mut ref_depth = RefDepth(vec![]);
165
166        for field in fields_clone {
167            if let Some(def_field) = model_config_field_map.get(&field.name) {
168                let include = Self::build_for_field(def_field, &field, model_map, &mut ref_depth)?;
169                include_fields.push(include);
170            }
171        }
172
173        include_fields.shrink_to_fit();
174        Ok((include_fields, ref_depth))
175    }
176
177    fn marry(
178        &self,
179        builder: &mut flexbuffers::VectorBuilder,
180        reader: &VectorReader<&[u8]>,
181    ) -> anyhow::Result<()> {
182        match self {
183            Include::Field(idx, kind) => {
184                kind.copy_to(&reader.idx(*idx as usize), builder, None)?;
185            }
186            Include::Fields(idx, fields, is_list) => {
187                let mut nested = builder.start_vector();
188                let reader = reader.idx(*idx as usize).as_vector();
189
190                if *is_list {
191                    for list_reader in &reader {
192                        let mut builder = nested.start_vector();
193
194                        for field in fields {
195                            field.marry(&mut builder, &list_reader.as_vector())?;
196                        }
197
198                        builder.end_vector();
199                    }
200                } else {
201                    for field in fields {
202                        field.marry(&mut nested, &reader)?;
203                    }
204                }
205
206                nested.end_vector();
207            }
208        }
209
210        Ok(())
211    }
212}
213
214#[derive(Clone, Debug)]
215enum QueryKind {
216    /// path position, whether it's a wildcard
217    Segment(usize, bool),
218    /// token field idx
219    Token(u8),
220    /// if there is no query
221    None,
222}
223
224#[derive(Clone, Debug)]
225enum Query {
226    /// model kind, field idx, type
227    Model(
228        u8,
229        u8,
230        Kind,
231        RefDepth,
232        Option<ordinary_storage::QueryExpression>,
233    ),
234    /// def idx, field idx, type
235    Content(u8, u8, Kind),
236
237    /// def idx
238    ContentMulti(u8),
239}
240
241#[derive(Clone)]
242pub struct Template {
243    pub idx: u8,
244    pub mime: HeaderValue,
245    pub reporting_endpoints: (HeaderName, HeaderValue),
246    pub config: TemplateConfig,
247
248    pub cache_control: Option<String>,
249    pub csp: Arc<RwLock<Option<HeaderValue>>>,
250
251    globals: Option<Bytes>,
252    fields: Option<Bytes>,
253
254    engine: Engine,
255    module: Arc<RwLock<Option<Module>>>,
256
257    storage: Arc<Storage>,
258
259    queries: Option<Vec<(Query, QueryKind, Vec<Include>)>>,
260}
261
262impl Template {
263    #[allow(clippy::too_many_lines, clippy::too_many_arguments)]
264    #[instrument(
265        name = "template"
266        skip_all,
267        fields(i, nm),
268        err
269    )]
270    pub fn new(
271        domain: &str,
272        secure: bool,
273
274        src: Option<Bytes>,
275
276        config: TemplateConfig,
277        auth: Arc<Auth>,
278        model_map: &HashMap<String, ModelConfig>,
279        content_map: &HashMap<String, ContentDefinition>,
280
281        globals: Option<Bytes>,
282        fields: Option<Bytes>,
283
284        engine: Engine,
285        storage: Arc<Storage>,
286    ) -> anyhow::Result<Template> {
287        tracing::Span::current().record("i", config.idx);
288        tracing::Span::current().record("nm", tracing::field::display(&config.name));
289
290        let (module, csp) = if let Some(src) = src {
291            let root = flexbuffers::Reader::get_root(src.as_ref())?;
292            let root_vec = root.as_vector();
293
294            if let Ok(module) = Module::new(&engine, root_vec.idx(1).as_blob().0) {
295                let csp = if matches!(
296                    config.mime.as_str(),
297                    "text/html" | "text/html; charset=utf-8" | "text/xml"
298                ) {
299                    Some(HeaderValue::from_str(root_vec.idx(0).as_str())?)
300                } else {
301                    None
302                };
303
304                (
305                    Arc::new(RwLock::new(Some(module))),
306                    Arc::new(RwLock::new(csp)),
307                )
308            } else {
309                (Arc::new(RwLock::new(None)), Arc::new(RwLock::new(None)))
310            }
311        } else {
312            (Arc::new(RwLock::new(None)), Arc::new(RwLock::new(None)))
313        };
314
315        tracing::info!("init");
316
317        let mut queries = vec![];
318
319        // todo: disallow conflicting bindings
320
321        if let Some(content_refs) = &config.content {
322            for content_ref in content_refs {
323                if let Some(content_def) = content_map.get(&content_ref.name) {
324                    let mut def_fields_map = BTreeMap::new();
325
326                    for field in &content_def.fields {
327                        def_fields_map.insert(field.name.clone(), field);
328                    }
329
330                    let include_fields = Include::build_for_content(content_def, content_ref)?;
331
332                    if content_ref.all.is_some() {
333                        queries.push((
334                            content_ref.idx,
335                            Query::ContentMulti(content_def.idx),
336                            QueryKind::None,
337                            include_fields.clone(),
338                        ));
339                    }
340
341                    for ref_field in &content_ref.fields {
342                        if let Some(def_field) = def_fields_map.get(&ref_field.name)
343                            && let Some(binding) = &ref_field.bind
344                        {
345                            match binding {
346                                TemplateRefFieldBind::Segment {
347                                    name,
348                                    expression: _,
349                                } => {
350                                    let mut path_pos = None;
351
352                                    for (i, segment) in config.route.split('/').enumerate() {
353                                        if segment == format!("{{{name}}}") {
354                                            path_pos = Some((i, name.starts_with('*')));
355                                        }
356                                    }
357
358                                    if let Some((path_pos, is_wildcard)) = path_pos {
359                                        queries.push((
360                                            content_ref.idx,
361                                            Query::Content(
362                                                content_def.idx,
363                                                def_field.idx,
364                                                def_field.kind.clone(),
365                                            ),
366                                            QueryKind::Segment(path_pos, is_wildcard),
367                                            include_fields.clone(),
368                                        ));
369                                    } else {
370                                        bail!(
371                                            "cannot bind to segment {{{name}}} as it is not present in the route"
372                                        );
373                                    }
374                                }
375                                TemplateRefFieldBind::Token {
376                                    field,
377                                    expression: _,
378                                } => {
379                                    let mut auth_field_idx = None;
380
381                                    for auth_field in &auth.config.access_token.claims {
382                                        if &auth_field.name == field {
383                                            auth_field_idx = Some(auth_field.idx);
384                                        }
385                                    }
386
387                                    if let Some(idx) = auth_field_idx {
388                                        queries.push((
389                                            content_ref.idx,
390                                            Query::Content(
391                                                content_def.idx,
392                                                def_field.idx,
393                                                def_field.kind.clone(),
394                                            ),
395                                            QueryKind::Token(idx),
396                                            include_fields.clone(),
397                                        ));
398                                    } else {
399                                        bail!("auth field {field} does not exist");
400                                    }
401                                }
402                            }
403                        }
404                    }
405                }
406            }
407        }
408
409        if let Some(model_refs) = &config.models {
410            for model_ref in model_refs {
411                if let Some(model_config) = model_map.get(&model_ref.name) {
412                    let mut model_config_fields_map = BTreeMap::new();
413
414                    let mut model_config = (*model_config).clone();
415
416                    let uuid_field = Field {
417                        idx: 0,
418                        name: "uuid".into(),
419                        kind: Kind::Uuid,
420                        indexed: Some(true),
421                        queryable: None,
422                        searchable: None,
423                        mapping: None,
424                        doc: None,
425                        encrypted: None,
426                        compressed: None,
427                    };
428
429                    let mut new_fields = model_config.fields.clone();
430                    new_fields.splice(0..0, vec![uuid_field]);
431
432                    model_config.fields = new_fields;
433
434                    for field in &model_config.fields {
435                        model_config_fields_map.insert(field.name.clone(), field);
436                    }
437
438                    let (include_fields, ref_depth) =
439                        Include::build_for_model(&model_config, model_ref, model_map)?;
440
441                    for ref_field in &model_ref.fields {
442                        if let Some(config_field) = model_config_fields_map.get(&ref_field.name)
443                            && let Some(binding) = &ref_field.bind
444                        {
445                            match binding {
446                                TemplateRefFieldBind::Segment { name, expression } => {
447                                    let mut path_pos = None;
448
449                                    for (i, segment) in config.route.split('/').enumerate() {
450                                        if segment == format!("{{{name}}}") {
451                                            path_pos = Some((i, name.starts_with('*')));
452                                        }
453                                    }
454
455                                    let exp = match expression {
456                                        Some(exp) => match exp {
457                                            QueryExpression::Gte => {
458                                                Some(ordinary_storage::QueryExpression::Gte)
459                                            }
460                                            QueryExpression::Lte => {
461                                                Some(ordinary_storage::QueryExpression::Lte)
462                                            }
463                                            QueryExpression::Gt => {
464                                                Some(ordinary_storage::QueryExpression::Gt)
465                                            }
466                                            QueryExpression::Lt => {
467                                                Some(ordinary_storage::QueryExpression::Lt)
468                                            }
469                                            QueryExpression::Eq => {
470                                                Some(ordinary_storage::QueryExpression::Eq)
471                                            }
472                                            QueryExpression::BeginsWith => {
473                                                Some(ordinary_storage::QueryExpression::BeginsWith)
474                                            }
475                                        },
476                                        None => None,
477                                    };
478
479                                    if let Some((path_pos, is_wildcard)) = path_pos {
480                                        queries.push((
481                                            model_ref.idx,
482                                            Query::Model(
483                                                model_config.idx,
484                                                config_field.idx,
485                                                config_field.kind.clone(),
486                                                ref_depth.clone(),
487                                                exp,
488                                            ),
489                                            QueryKind::Segment(path_pos, is_wildcard),
490                                            include_fields.clone(),
491                                        ));
492                                    } else {
493                                        bail!(
494                                            "cannot bind to segment {{{name}}} as it is not present in the route"
495                                        );
496                                    }
497                                }
498                                TemplateRefFieldBind::Token { field, expression } => {
499                                    let mut auth_field_idx = None;
500
501                                    for auth_field in &auth.config.access_token.claims {
502                                        if &auth_field.name == field {
503                                            auth_field_idx = Some(auth_field.idx);
504                                        }
505                                    }
506
507                                    let exp = match expression {
508                                        Some(exp) => match exp {
509                                            QueryExpression::Gte => {
510                                                Some(ordinary_storage::QueryExpression::Gte)
511                                            }
512                                            QueryExpression::Lte => {
513                                                Some(ordinary_storage::QueryExpression::Lte)
514                                            }
515                                            QueryExpression::Gt => {
516                                                Some(ordinary_storage::QueryExpression::Gt)
517                                            }
518                                            QueryExpression::Lt => {
519                                                Some(ordinary_storage::QueryExpression::Lt)
520                                            }
521                                            QueryExpression::Eq => {
522                                                Some(ordinary_storage::QueryExpression::Eq)
523                                            }
524                                            QueryExpression::BeginsWith => {
525                                                Some(ordinary_storage::QueryExpression::BeginsWith)
526                                            }
527                                        },
528                                        None => None,
529                                    };
530
531                                    if let Some(idx) = auth_field_idx {
532                                        queries.push((
533                                            model_ref.idx,
534                                            Query::Model(
535                                                model_config.idx,
536                                                config_field.idx,
537                                                config_field.kind.clone(),
538                                                ref_depth.clone(),
539                                                exp,
540                                            ),
541                                            QueryKind::Token(idx),
542                                            include_fields.clone(),
543                                        ));
544                                    } else {
545                                        bail!("auth field {field} does not exist");
546                                    }
547                                }
548                            }
549                        }
550                    }
551                }
552            }
553        }
554
555        let mut cache_control = String::new();
556
557        if let Some(cache) = &config.cache
558            && let Some(http_cache) = &cache.http
559            && let Some(http_cache_control) = &http_cache.cache_control
560        {
561            // todo: make the default configurable by the API server
562            http_cache_control.header_value(&mut cache_control, "")?;
563        } else {
564            // todo: set a default for the cache control (dictated by Ordinary API Server)
565        }
566
567        let reporting_endpoints = format!(
568            "csp=\"http{}://{domain}/.ordinary/reports/csp\"",
569            if secure { "s" } else { "" }
570        );
571
572        Ok(Template {
573            idx: config.idx,
574            mime: HeaderValue::from_str(config.mime.as_str())?,
575            reporting_endpoints: (
576                HeaderName::from_static("reporting-endpoints"),
577                HeaderValue::from_str(reporting_endpoints.as_str())?,
578            ),
579
580            config,
581
582            cache_control: if cache_control.is_empty() {
583                None
584            } else {
585                Some(cache_control)
586            },
587
588            csp,
589
590            engine,
591            module,
592            storage,
593
594            globals,
595            fields,
596
597            queries: if queries.is_empty() {
598                None
599            } else {
600                queries.sort_by_key(|a| a.0);
601                let mut queries = queries
602                    .iter()
603                    .map(|(_, q, qk, i)| (q.clone(), qk.clone(), i.clone()))
604                    .collect::<Vec<_>>();
605
606                queries.shrink_to_fit();
607
608                Some(queries)
609            },
610        })
611    }
612
613    pub fn start_tasks(&self) {
614        if let Some(cache_config) = &self.config.cache
615            && let Some(stored_cache) = &cache_config.stored
616        {
617            let storage_clone = self.storage.clone();
618
619            let cache_config_clone = stored_cache.clone();
620            let idx = self.config.idx;
621
622            let template_span =
623                info_span!("template", i = &self.config.idx, nm = %self.config.name);
624
625            let cache_span = template_span.in_scope(|| info_span!("cache"));
626
627            if let StoredCachePolicy::Permanent = stored_cache.policy {
628                // don't start the cache_clean task
629            } else {
630                // todo: pass this default and a range check from Ordinary API
631                let (mut clean_min, mut clean_max) =
632                    cache_config_clone.clean_interval.unwrap_or((60, 60 * 3));
633
634                clean_min *= 1000;
635                clean_max *= 1000;
636
637                tokio::spawn(async move {
638                    loop {
639                        // todo: break on app kill
640
641                        let cache_clean_interval_ms = rand::random_range(clean_min..clean_max);
642
643                        tokio::time::sleep(Duration::from_millis(cache_clean_interval_ms)).await;
644
645                        async {
646                            if let Err(err) = storage_clone
647                                .cache
648                                .clean_cache(&CacheRead::Template, &cache_config_clone, idx)
649                                .await
650                            {
651                                tracing::error!(%err, "failed to clean cache");
652                            }
653                        }
654                        .instrument(cache_span.clone())
655                        .await;
656                    }
657                });
658            }
659        }
660    }
661
662    #[instrument(skip_all, err)]
663    pub async fn set_wasm(
664        &self,
665        src: &[u8],
666        app_config: &OrdinaryConfig,
667        csp_style: Option<Vec<String>>,
668        csp_script: Option<Vec<String>>,
669        secure: bool,
670    ) -> anyhow::Result<()> {
671        let storage_span = info_span!("storage");
672        let span = storage_span.in_scope(|| info_span!("artifact"));
673
674        #[cfg(feature = "studio")]
675        let script_urls = Some(vec![IFRAME_RESIZER_CHILD_URL.to_string()]);
676
677        #[cfg(not(feature = "studio"))]
678        let script_urls = None;
679
680        let csp_string = self.config.csp.clone().unwrap_or_default().build_string(
681            &app_config.csp.clone().unwrap_or_default(),
682            csp_style,
683            csp_script,
684            script_urls,
685            secure,
686            app_config.has_ordinary_actions() || app_config.auth.is_some(),
687        );
688
689        let mut builder = flexbuffers::Builder::new(&flexbuffers::BuilderOptions::SHARE_NONE);
690        let mut builder_vec = builder.start_vector();
691
692        builder_vec.push(csp_string.as_str());
693        builder_vec.push(flexbuffers::Blob(src));
694
695        builder_vec.end_vector();
696
697        span.in_scope(|| {
698            self.storage
699                .artifact
700                .put(self.idx, ArtifactKind::Template, builder.view())
701        })?;
702
703        {
704            let mut lock = self.module.write();
705            let module = Module::new(&self.engine, src)?;
706
707            *lock = Some(module);
708        }
709
710        if let Ok(mime) = self.mime.to_str()
711            && matches!(mime, "text/html" | "text/html; charset=utf-8" | "text/xml")
712        {
713            let mut lock = self.csp.write();
714
715            *lock = Some(HeaderValue::from_str(csp_string.as_str())?);
716            drop(lock);
717        }
718
719        let span = storage_span.in_scope(|| info_span!("cache"));
720
721        async {
722            self.storage
723                .cache
724                .artifact_evict(CacheRead::Template, self.idx)
725                .await
726        }
727        .instrument(span)
728        .await?;
729
730        Ok(())
731    }
732
733    #[instrument(skip_all, err)]
734    pub fn render(
735        &self,
736        host: &str,
737        path: String,
738        params: Option<String>,
739        // message and code
740        error: Option<(String, u16)>,
741        // svg qr_code, account and recovery_codes
742        totp: Option<(String, String, String)>,
743        claims: &Option<VectorReader<&[u8]>>,
744    ) -> anyhow::Result<TemplateResult> {
745        let args = self.query(host, path, params, error, totp, claims)?;
746
747        match self.config.ffi.version {
748            TemplateFfiVersion::V1 => {
749                #[cfg(not(feature = "studio"))]
750                {
751                    ffi::v1::call(self, &args)
752                }
753
754                #[cfg(feature = "studio")]
755                {
756                    if self.config.mime.contains("html") {
757                        let res = ffi::v1::call(self, &args)?;
758
759                        match res {
760                            TemplateResult::StatusCode(_) => Ok(res),
761                            TemplateResult::Result(bytes) => {
762                                let str = std::str::from_utf8(bytes.as_ref())?;
763
764                                let res = if str.contains("<head>") {
765                                    str.replace("<head>", &format!(r#"<head><script async src="{IFRAME_RESIZER_CHILD_URL}"></script>"#))
766                                } else {
767                                    str.replace("<html lang=en>", &format!(r#"<html lang=en><script async src="{IFRAME_RESIZER_CHILD_URL}"></script>"#))
768                                };
769
770                                Ok(TemplateResult::Result(Bytes::copy_from_slice(
771                                    res.as_bytes(),
772                                )))
773                            }
774                        }
775                    } else {
776                        ffi::v1::call(self, &args)
777                    }
778                }
779            }
780        }
781    }
782
783    // accepts token + bound arguments and then uses config to go request all the stuff
784    #[allow(clippy::too_many_lines)]
785    #[instrument(skip_all, err)]
786    pub fn query(
787        &self,
788        host: &str,
789        path: String,
790        params: Option<String>,
791        // message and code
792        error: Option<(String, u16)>,
793        // svg qr_code, account and recovery_codes
794        totp: Option<(String, String, String)>,
795        claims: &Option<VectorReader<&[u8]>>,
796    ) -> anyhow::Result<Bytes> {
797        let mut builder = flexbuffers::Builder::new(&flexbuffers::BuilderOptions::SHARE_NONE);
798        let mut vec_builder = builder.start_vector();
799
800        if let Some(queries) = &self.queries {
801            let segments: Vec<&str> = path.split('/').collect();
802
803            let _params_map = match params {
804                Some(_params) => {
805                    let params_map: BTreeMap<String, String> = BTreeMap::new();
806                    // todo: update params map
807                    Some(params_map)
808                }
809                None => None,
810            };
811
812            // todo: push params into
813
814            // todo: push flags into
815
816            for (query, query_kind, includes) in queries {
817                let kind = match query {
818                    Query::Model(_, _, kind, _, _) | Query::Content(_, _, kind) => kind,
819                    Query::ContentMulti(_) => &Kind::Void,
820                };
821
822                let indexed_val: Bytes = match query_kind {
823                    QueryKind::Segment(pos, is_wildcard) => {
824                        if pos <= &segments.len() {
825                            let val = if *is_wildcard {
826                                let mut out = String::new();
827
828                                for (i, segment) in segments.iter().enumerate() {
829                                    if i == *pos {
830                                        (*segment).clone_into(&mut out);
831                                    } else if i > *pos {
832                                        out = format!("{out}/{segment}");
833                                    }
834                                }
835
836                                out
837                            } else {
838                                segments[*pos].to_string()
839                            };
840
841                            match kind {
842                                Kind::Uuid => {
843                                    let uuid = uuid::Uuid::from_str(&val)?;
844                                    Bytes::copy_from_slice(uuid.as_bytes())
845                                }
846                                _ => Bytes::copy_from_slice(val.as_bytes()),
847                            }
848                        } else {
849                            bail!("position out of bounds for route");
850                        }
851                    }
852                    QueryKind::Token(field_idx) => {
853                        if let Some(claims) = claims {
854                            let reader = claims.idx(*field_idx as usize);
855
856                            match kind {
857                                Kind::Uuid => Bytes::copy_from_slice(reader.as_blob().0),
858                                Kind::String => Bytes::copy_from_slice(reader.as_str().as_bytes()),
859                                _ => Bytes::new(),
860                            }
861                        } else {
862                            bail!("no claims on query");
863                        }
864                    }
865                    QueryKind::None => Bytes::new(),
866                };
867
868                let span = info_span!("storage");
869
870                match query {
871                    Query::Content(def_idx, field_idx, _kind) => {
872                        let content_obj = span.in_scope(|| {
873                            let content_span = info_span!("content");
874
875                            content_span.in_scope(|| {
876                                self.storage.content.get(*def_idx, *field_idx, &indexed_val)
877                            })
878                        })?;
879
880                        let root = flexbuffers::Reader::get_root(&content_obj[..])?;
881
882                        let mut fields_builder = vec_builder.start_vector();
883
884                        for include in includes {
885                            include.marry(&mut fields_builder, &root.as_vector())?;
886                        }
887
888                        fields_builder.end_vector();
889                    }
890                    Query::ContentMulti(def_idx) => {
891                        let content_objs = span.in_scope(|| {
892                            let content_span = info_span!("content");
893
894                            content_span.in_scope(|| self.storage.content.list(*def_idx))
895                        })?;
896
897                        let root = flexbuffers::Reader::get_root(&content_objs[..])?;
898
899                        let mut object_vector = vec_builder.start_vector();
900
901                        for object in &root.as_vector() {
902                            let obj_bytes = object.as_blob().0;
903
904                            let object = flexbuffers::Reader::get_root(obj_bytes)?;
905
906                            let mut fields_builder = object_vector.start_vector();
907
908                            for include in includes {
909                                include.marry(&mut fields_builder, &object.as_vector())?;
910                            }
911
912                            fields_builder.end_vector();
913                        }
914
915                        object_vector.end_vector();
916                    }
917                    Query::Model(model_kind, field_idx, _kind, ref_depth, expression) => {
918                        if let Some(exp) = expression {
919                            let items = span.in_scope(|| {
920                                self.storage.model.query_model(
921                                    *model_kind,
922                                    *field_idx,
923                                    exp.as_byte(),
924                                    &indexed_val,
925                                    ref_depth,
926                                    None,
927                                )
928                            })?;
929
930                            let root = flexbuffers::Reader::get_root(&items[..])?;
931
932                            let mut item_builder = vec_builder.start_vector();
933
934                            for item in &root.as_vector() {
935                                let mut fields_builder = item_builder.start_vector();
936
937                                for include in includes {
938                                    include.marry(&mut fields_builder, &item.as_vector())?;
939                                }
940
941                                fields_builder.end_vector();
942                            }
943
944                            item_builder.end_vector();
945                        } else {
946                            let model_item = span.in_scope(|| {
947                                self.storage.model.get_model(
948                                    *model_kind,
949                                    *field_idx,
950                                    &indexed_val,
951                                    ref_depth,
952                                    None,
953                                )
954                            })?;
955
956                            let root = flexbuffers::Reader::get_root(&model_item[..])?;
957
958                            let mut fields_builder = vec_builder.start_vector();
959
960                            for include in includes {
961                                include.marry(&mut fields_builder, &root.as_vector())?;
962                            }
963
964                            fields_builder.end_vector();
965                        }
966                    }
967                }
968            }
969        }
970
971        if let Some(error) = error {
972            let mut error_builder = vec_builder.start_vector();
973
974            error_builder.push(error.0.as_str());
975            error_builder.push(error.1);
976
977            error_builder.end_vector();
978        }
979
980        if let Some(totp) = totp {
981            let mut totp_builder = vec_builder.start_vector();
982
983            totp_builder.push(totp.0.as_str());
984            totp_builder.push(totp.1.as_str());
985
986            let mut recovery_codes_vec = totp_builder.start_vector();
987
988            let mut chunk = String::new();
989
990            for (i, c) in totp.2.chars().enumerate() {
991                if i != 0 && i % 11 == 0 {
992                    recovery_codes_vec.push(chunk.as_str());
993                    chunk = String::new();
994                } else {
995                    chunk = format!("{chunk}{c}");
996                }
997            }
998
999            recovery_codes_vec.end_vector();
1000
1001            totp_builder.end_vector();
1002        }
1003
1004        vec_builder.push(host);
1005
1006        if let Some(globals) = &self.globals {
1007            vec_builder.push(flexbuffers::Blob(globals.as_ref()));
1008        }
1009        if let Some(fields) = &self.fields {
1010            vec_builder.push(flexbuffers::Blob(fields.as_ref()));
1011        }
1012
1013        vec_builder.end_vector();
1014
1015        Ok(Bytes::copy_from_slice(builder.view()))
1016    }
1017}