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
33use ordinary_utils::REPORTING_ENDPOINTS;
34pub use wasmtime::Engine;
35
36#[cfg(feature = "studio")]
37const IFRAME_RESIZER_CHILD_URL: &str = "https://cdn.jsdelivr.net/npm/@iframe-resizer/child@5.5.9";
38
39#[derive(Clone, Debug, PartialEq)]
40pub enum TemplateResult {
41    Result(Bytes),
42    StatusCode(StatusCode),
43}
44
45#[derive(Clone, Debug)]
46enum Include {
47    Field(u8, Kind),
48    Fields(u8, Vec<Include>, bool),
49}
50
51impl Include {
52    fn build_for_field(
53        field: &Field,
54        ref_field: &TemplateRefField,
55        model_map: &HashMap<String, ModelConfig>,
56        ref_depth: &mut RefDepth,
57    ) -> anyhow::Result<Self> {
58        let field_idx = field.idx;
59
60        match &ref_field.fields {
61            Some(nested_ref_fields) => {
62                let mut nested = vec![];
63                let mut is_list = false;
64
65                let mut nested_field_map = HashMap::new();
66
67                match &field.kind {
68                    Kind::List { kind } => {
69                        if let Kind::Object { name: _, fields } = &**kind {
70                            for nested_field in fields {
71                                nested_field_map.insert(nested_field.name.clone(), nested_field);
72                            }
73
74                            is_list = true;
75                        } else {
76                            bail!("cannot have nested fields on non object");
77                        }
78                    }
79                    Kind::Object { name: _, fields } => {
80                        for nested_field in fields {
81                            nested_field_map.insert(nested_field.name.clone(), nested_field);
82                        }
83                    }
84                    Kind::Ref {
85                        model,
86                        field: _,
87                        many: _,
88                    } => {
89                        if let Some(model) = model_map.get(model) {
90                            for nested_field in &model.fields {
91                                nested_field_map.insert(nested_field.name.clone(), nested_field);
92                            }
93
94                            ref_depth.0.push(((field.idx, 1, None), RefDepth(vec![])));
95                        }
96                    }
97                    _ => bail!("cannot have nested fields on non object"),
98                }
99
100                let mut fields_clone = nested_ref_fields.clone();
101                fields_clone.sort_by_key(|a| a.idx);
102
103                for nested_ref_field in fields_clone {
104                    if let Some(nested_field) = nested_field_map.get(&nested_ref_field.name) {
105                        nested.push(Self::build_for_field(
106                            nested_field,
107                            &nested_ref_field,
108                            model_map,
109                            ref_depth,
110                        )?);
111                    }
112                }
113
114                nested.shrink_to_fit();
115                Ok(Include::Fields(field_idx, nested, is_list))
116            }
117            None => Ok(Include::Field(field_idx, field.kind.clone())),
118        }
119    }
120
121    fn build_for_content(
122        content_def: &ContentDefinition,
123        template_ref: &TemplateRef,
124    ) -> anyhow::Result<Vec<Self>> {
125        let mut include_fields = vec![];
126
127        let mut fields_clone = template_ref.fields.clone();
128        fields_clone.sort_by_key(|a| a.idx);
129
130        let mut content_def_field_map = HashMap::new();
131        for field in &content_def.fields {
132            content_def_field_map.insert(field.name.clone(), field);
133        }
134
135        for field in fields_clone {
136            if let Some(def_field) = content_def_field_map.get(&field.name) {
137                let include = Self::build_for_field(
138                    def_field,
139                    &field,
140                    &HashMap::new(),
141                    &mut RefDepth(vec![]),
142                )?;
143                include_fields.push(include);
144            }
145        }
146
147        include_fields.shrink_to_fit();
148        Ok(include_fields)
149    }
150
151    fn build_for_model(
152        model_config: &ModelConfig,
153        template_ref: &TemplateRef,
154        model_map: &HashMap<String, ModelConfig>,
155    ) -> anyhow::Result<(Vec<Self>, RefDepth)> {
156        let mut include_fields = vec![];
157
158        let mut fields_clone = template_ref.fields.clone();
159        fields_clone.sort_by_key(|a| a.idx);
160
161        let mut model_config_field_map = HashMap::new();
162        for field in &model_config.fields {
163            model_config_field_map.insert(field.name.clone(), field);
164        }
165        let mut ref_depth = RefDepth(vec![]);
166
167        for field in fields_clone {
168            if let Some(def_field) = model_config_field_map.get(&field.name) {
169                let include = Self::build_for_field(def_field, &field, model_map, &mut ref_depth)?;
170                include_fields.push(include);
171            }
172        }
173
174        include_fields.shrink_to_fit();
175        Ok((include_fields, ref_depth))
176    }
177
178    fn marry(
179        &self,
180        builder: &mut flexbuffers::VectorBuilder,
181        reader: &VectorReader<&[u8]>,
182    ) -> anyhow::Result<()> {
183        match self {
184            Include::Field(idx, kind) => {
185                kind.copy_to(&reader.idx(*idx as usize), builder, None)?;
186            }
187            Include::Fields(idx, fields, is_list) => {
188                let mut nested = builder.start_vector();
189                let reader = reader.idx(*idx as usize).as_vector();
190
191                if *is_list {
192                    for list_reader in &reader {
193                        let mut builder = nested.start_vector();
194
195                        for field in fields {
196                            field.marry(&mut builder, &list_reader.as_vector())?;
197                        }
198
199                        builder.end_vector();
200                    }
201                } else {
202                    for field in fields {
203                        field.marry(&mut nested, &reader)?;
204                    }
205                }
206
207                nested.end_vector();
208            }
209        }
210
211        Ok(())
212    }
213}
214
215#[derive(Clone, Debug)]
216enum QueryKind {
217    /// path position, whether it's a wildcard
218    Segment(usize, bool),
219    /// token field idx
220    Token(u8),
221    /// if there is no query
222    None,
223}
224
225#[derive(Clone, Debug)]
226enum Query {
227    /// model kind, field idx, type
228    Model(
229        u8,
230        u8,
231        Kind,
232        RefDepth,
233        Option<ordinary_storage::QueryExpression>,
234    ),
235    /// def idx, field idx, type
236    Content(u8, u8, Kind),
237
238    /// def idx
239    ContentMulti(u8),
240}
241
242#[derive(Clone)]
243pub struct Template {
244    pub idx: u8,
245    pub mime: HeaderValue,
246    pub reporting_endpoints: (HeaderName, HeaderValue),
247    pub config: TemplateConfig,
248
249    pub cache_control: Option<String>,
250    pub csp: Arc<RwLock<Option<HeaderValue>>>,
251
252    globals: Option<Bytes>,
253    fields: Option<Bytes>,
254
255    engine: Engine,
256    module: Arc<RwLock<Option<Module>>>,
257
258    storage: Arc<Storage>,
259
260    queries: Option<Vec<(Query, QueryKind, Vec<Include>)>>,
261}
262
263impl Template {
264    #[allow(clippy::too_many_lines, clippy::too_many_arguments)]
265    #[instrument(
266        name = "tmp"
267        skip_all,
268        fields(i, nm),
269        err
270    )]
271    pub fn new(
272        domain: &str,
273        secure: bool,
274
275        src: Option<Bytes>,
276
277        config: TemplateConfig,
278        auth: Arc<Auth>,
279        model_map: &HashMap<String, ModelConfig>,
280        content_map: &HashMap<String, ContentDefinition>,
281
282        globals: Option<Bytes>,
283        fields: Option<Bytes>,
284
285        engine: Engine,
286        storage: Arc<Storage>,
287    ) -> anyhow::Result<Template> {
288        tracing::Span::current().record("i", config.idx);
289        tracing::Span::current().record("nm", tracing::field::display(&config.name));
290
291        let (module, csp) = if let Some(src) = src {
292            let root = flexbuffers::Reader::get_root(src.as_ref())?;
293            let root_vec = root.as_vector();
294
295            if let Ok(module) = Module::new(&engine, root_vec.idx(1).as_blob().0) {
296                let csp = if matches!(
297                    config.mime.as_str(),
298                    "text/html" | "text/html; charset=utf-8" | "text/xml"
299                ) {
300                    Some(HeaderValue::from_str(root_vec.idx(0).as_str())?)
301                } else {
302                    None
303                };
304
305                (
306                    Arc::new(RwLock::new(Some(module))),
307                    Arc::new(RwLock::new(csp)),
308                )
309            } else {
310                (Arc::new(RwLock::new(None)), Arc::new(RwLock::new(None)))
311            }
312        } else {
313            (Arc::new(RwLock::new(None)), Arc::new(RwLock::new(None)))
314        };
315
316        tracing::info!("init");
317
318        let mut queries = vec![];
319
320        // todo: disallow conflicting bindings
321
322        if let Some(content_refs) = &config.content {
323            for content_ref in content_refs {
324                if let Some(content_def) = content_map.get(&content_ref.name) {
325                    let mut def_fields_map = BTreeMap::new();
326
327                    for field in &content_def.fields {
328                        def_fields_map.insert(field.name.clone(), field);
329                    }
330
331                    let include_fields = Include::build_for_content(content_def, content_ref)?;
332
333                    if content_ref.all.is_some() {
334                        queries.push((
335                            content_ref.idx,
336                            Query::ContentMulti(content_def.idx),
337                            QueryKind::None,
338                            include_fields.clone(),
339                        ));
340                    }
341
342                    for ref_field in &content_ref.fields {
343                        if let Some(def_field) = def_fields_map.get(&ref_field.name)
344                            && let Some(binding) = &ref_field.bind
345                        {
346                            match binding {
347                                TemplateRefFieldBind::Segment {
348                                    name,
349                                    expression: _,
350                                } => {
351                                    let mut path_pos = None;
352
353                                    for (i, segment) in config.route.split('/').enumerate() {
354                                        if segment == format!("{{{name}}}") {
355                                            path_pos = Some((i, name.starts_with('*')));
356                                        }
357                                    }
358
359                                    if let Some((path_pos, is_wildcard)) = path_pos {
360                                        queries.push((
361                                            content_ref.idx,
362                                            Query::Content(
363                                                content_def.idx,
364                                                def_field.idx,
365                                                def_field.kind.clone(),
366                                            ),
367                                            QueryKind::Segment(path_pos, is_wildcard),
368                                            include_fields.clone(),
369                                        ));
370                                    } else {
371                                        bail!(
372                                            "cannot bind to segment {{{name}}} as it is not present in the route"
373                                        );
374                                    }
375                                }
376                                TemplateRefFieldBind::Token {
377                                    field,
378                                    expression: _,
379                                } => {
380                                    let mut auth_field_idx = None;
381
382                                    for auth_field in &auth.config.access_token.claims {
383                                        if &auth_field.name == field {
384                                            auth_field_idx = Some(auth_field.idx);
385                                        }
386                                    }
387
388                                    if let Some(idx) = auth_field_idx {
389                                        queries.push((
390                                            content_ref.idx,
391                                            Query::Content(
392                                                content_def.idx,
393                                                def_field.idx,
394                                                def_field.kind.clone(),
395                                            ),
396                                            QueryKind::Token(idx),
397                                            include_fields.clone(),
398                                        ));
399                                    } else {
400                                        bail!("auth field {field} does not exist");
401                                    }
402                                }
403                            }
404                        }
405                    }
406                }
407            }
408        }
409
410        if let Some(model_refs) = &config.models {
411            for model_ref in model_refs {
412                if let Some(model_config) = model_map.get(&model_ref.name) {
413                    let mut model_config_fields_map = BTreeMap::new();
414
415                    let mut model_config = (*model_config).clone();
416
417                    let uuid_field = Field {
418                        idx: 0,
419                        name: "uuid".into(),
420                        kind: Kind::Uuid,
421                        indexed: Some(true),
422                        queryable: None,
423                        searchable: None,
424                        mapping: None,
425                        doc: None,
426                        encrypted: None,
427                        compressed: None,
428                    };
429
430                    let mut new_fields = model_config.fields.clone();
431                    new_fields.splice(0..0, vec![uuid_field]);
432
433                    model_config.fields = new_fields;
434
435                    for field in &model_config.fields {
436                        model_config_fields_map.insert(field.name.clone(), field);
437                    }
438
439                    let (include_fields, ref_depth) =
440                        Include::build_for_model(&model_config, model_ref, model_map)?;
441
442                    for ref_field in &model_ref.fields {
443                        if let Some(config_field) = model_config_fields_map.get(&ref_field.name)
444                            && let Some(binding) = &ref_field.bind
445                        {
446                            match binding {
447                                TemplateRefFieldBind::Segment { name, expression } => {
448                                    let mut path_pos = None;
449
450                                    for (i, segment) in config.route.split('/').enumerate() {
451                                        if segment == format!("{{{name}}}") {
452                                            path_pos = Some((i, name.starts_with('*')));
453                                        }
454                                    }
455
456                                    let exp = match expression {
457                                        Some(exp) => match exp {
458                                            QueryExpression::Gte => {
459                                                Some(ordinary_storage::QueryExpression::Gte)
460                                            }
461                                            QueryExpression::Lte => {
462                                                Some(ordinary_storage::QueryExpression::Lte)
463                                            }
464                                            QueryExpression::Gt => {
465                                                Some(ordinary_storage::QueryExpression::Gt)
466                                            }
467                                            QueryExpression::Lt => {
468                                                Some(ordinary_storage::QueryExpression::Lt)
469                                            }
470                                            QueryExpression::Eq => {
471                                                Some(ordinary_storage::QueryExpression::Eq)
472                                            }
473                                            QueryExpression::BeginsWith => {
474                                                Some(ordinary_storage::QueryExpression::BeginsWith)
475                                            }
476                                        },
477                                        None => None,
478                                    };
479
480                                    if let Some((path_pos, is_wildcard)) = path_pos {
481                                        queries.push((
482                                            model_ref.idx,
483                                            Query::Model(
484                                                model_config.idx,
485                                                config_field.idx,
486                                                config_field.kind.clone(),
487                                                ref_depth.clone(),
488                                                exp,
489                                            ),
490                                            QueryKind::Segment(path_pos, is_wildcard),
491                                            include_fields.clone(),
492                                        ));
493                                    } else {
494                                        bail!(
495                                            "cannot bind to segment {{{name}}} as it is not present in the route"
496                                        );
497                                    }
498                                }
499                                TemplateRefFieldBind::Token { field, expression } => {
500                                    let mut auth_field_idx = None;
501
502                                    for auth_field in &auth.config.access_token.claims {
503                                        if &auth_field.name == field {
504                                            auth_field_idx = Some(auth_field.idx);
505                                        }
506                                    }
507
508                                    let exp = match expression {
509                                        Some(exp) => match exp {
510                                            QueryExpression::Gte => {
511                                                Some(ordinary_storage::QueryExpression::Gte)
512                                            }
513                                            QueryExpression::Lte => {
514                                                Some(ordinary_storage::QueryExpression::Lte)
515                                            }
516                                            QueryExpression::Gt => {
517                                                Some(ordinary_storage::QueryExpression::Gt)
518                                            }
519                                            QueryExpression::Lt => {
520                                                Some(ordinary_storage::QueryExpression::Lt)
521                                            }
522                                            QueryExpression::Eq => {
523                                                Some(ordinary_storage::QueryExpression::Eq)
524                                            }
525                                            QueryExpression::BeginsWith => {
526                                                Some(ordinary_storage::QueryExpression::BeginsWith)
527                                            }
528                                        },
529                                        None => None,
530                                    };
531
532                                    if let Some(idx) = auth_field_idx {
533                                        queries.push((
534                                            model_ref.idx,
535                                            Query::Model(
536                                                model_config.idx,
537                                                config_field.idx,
538                                                config_field.kind.clone(),
539                                                ref_depth.clone(),
540                                                exp,
541                                            ),
542                                            QueryKind::Token(idx),
543                                            include_fields.clone(),
544                                        ));
545                                    } else {
546                                        bail!("auth field {field} does not exist");
547                                    }
548                                }
549                            }
550                        }
551                    }
552                }
553            }
554        }
555
556        let mut cache_control = String::new();
557
558        if let Some(cache) = &config.cache
559            && let Some(http_cache) = &cache.http
560            && let Some(http_cache_control) = &http_cache.cache_control
561        {
562            // todo: make the default configurable by the API server
563            http_cache_control.header_value(&mut cache_control, "")?;
564        } else {
565            // todo: set a default for the cache control (dictated by Ordinary API Server)
566        }
567
568        let reporting_endpoints = format!(
569            "csp=\"http{}://{domain}/.ordinary/reports/csp\"",
570            if secure { "s" } else { "" }
571        );
572
573        Ok(Template {
574            idx: config.idx,
575            mime: HeaderValue::from_str(config.mime.as_str())?,
576            reporting_endpoints: (
577                REPORTING_ENDPOINTS,
578                HeaderValue::from_str(reporting_endpoints.as_str())?,
579            ),
580
581            config,
582
583            cache_control: if cache_control.is_empty() {
584                None
585            } else {
586                Some(cache_control)
587            },
588
589            csp,
590
591            engine,
592            module,
593            storage,
594
595            globals,
596            fields,
597
598            queries: if queries.is_empty() {
599                None
600            } else {
601                queries.sort_by_key(|a| a.0);
602                let mut queries = queries
603                    .iter()
604                    .map(|(_, q, qk, i)| (q.clone(), qk.clone(), i.clone()))
605                    .collect::<Vec<_>>();
606
607                queries.shrink_to_fit();
608
609                Some(queries)
610            },
611        })
612    }
613
614    pub fn start_tasks(&self) {
615        if let Some(cache_config) = &self.config.cache
616            && let Some(stored_cache) = &cache_config.stored
617        {
618            let storage_clone = self.storage.clone();
619
620            let cache_config_clone = stored_cache.clone();
621            let idx = self.config.idx;
622
623            let template_span = info_span!("tmp", 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}