Skip to main content

pharos_native/runtime/
json_commands.rs

1#![allow(clippy::too_many_arguments)]
2
3use std::fs;
4
5use std::path::{Component, Path, PathBuf};
6
7use saphyr::LoadableYamlNode;
8use serde_json::{Map, Value};
9use sha2::{Digest, Sha256};
10
11use crate::config;
12
13pub use super::database::{
14    dynamic_relational_backend, dynamic_relational_runtime_audit_count,
15    dynamic_relational_runtime_export_json, dynamic_relational_runtime_import_state,
16    dynamic_runtime_prepare, dynamic_runtime_ready, load_cli_backend_config,
17};
18use super::generated;
19
20#[derive(Debug, Clone, Eq, PartialEq)]
21struct MultipartPart {
22    name: String,
23    text: Option<String>,
24    filename: Option<String>,
25    content: Vec<u8>,
26}
27
28#[derive(Debug, Clone, Eq, PartialEq)]
29pub struct MultipartFilePart {
30    pub filename: String,
31    pub content: Vec<u8>,
32}
33
34/// Reads JSON file.
35fn read_json_file(path: &Path) -> Option<Value> {
36    serde_json::from_str(&fs::read_to_string(path).ok()?).ok()
37}
38
39/// Performs JSON string.
40fn json_string<'a>(value: &'a Value, key: &str) -> Option<&'a str> {
41    value.get(key).and_then(Value::as_str)
42}
43
44/// Bundles manifest slice order lines.
45///
46/// # Parameters
47///
48/// - `path`: Input consumed by [`crate::runtime::json_commands::bundle_manifest_slice_order_lines`].
49///
50/// # Returns
51///
52/// Returns [`Some`] when [`crate::runtime::json_commands::bundle_manifest_slice_order_lines`] can produce a value and [`None`] otherwise.
53///
54/// # Performance
55///
56/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::bundle_manifest_slice_order_lines`].
57///
58/// # Examples
59///
60/// ```rust,ignore
61/// let _result = pharos_native::runtime::json_commands::bundle_manifest_slice_order_lines(std::path::Path::new("fixture.json"));
62/// ```
63///
64/// # Related
65///
66/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
67pub fn bundle_manifest_slice_order_lines(path: &Path) -> Option<Vec<String>> {
68    let root = read_json_file(path)?;
69    let mut lines = Vec::new();
70    if let Some(slices) = root.get("slices").and_then(Value::as_array) {
71        for item in slices {
72            if let Some(path) = json_string(item, "path") {
73                lines.push(path.to_owned());
74            }
75        }
76    }
77    if lines.is_empty()
78        && let Some(slice_order) = root.get("slice_order").and_then(Value::as_array)
79    {
80        for item in slice_order {
81            if let Some(text) = item.as_str() {
82                lines.push(text.to_owned());
83            }
84        }
85    }
86    (!lines.is_empty()).then_some(lines)
87}
88
89/// Bundles manifest layer for slice.
90///
91/// # Parameters
92///
93/// - `path`: Input consumed by [`crate::runtime::json_commands::bundle_manifest_layer_for_slice`].
94/// - `slice_name`: Input consumed by [`crate::runtime::json_commands::bundle_manifest_layer_for_slice`].
95///
96/// # Returns
97///
98/// Returns [`Some`] when [`crate::runtime::json_commands::bundle_manifest_layer_for_slice`] can produce a value and [`None`] otherwise.
99///
100/// # Performance
101///
102/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::bundle_manifest_layer_for_slice`].
103///
104/// # Examples
105///
106/// ```rust,ignore
107/// let _result = pharos_native::runtime::json_commands::bundle_manifest_layer_for_slice(std::path::Path::new("fixture.json"), "slice");
108/// ```
109///
110/// # Related
111///
112/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
113pub fn bundle_manifest_layer_for_slice(path: &Path, slice_name: &str) -> Option<Option<String>> {
114    if slice_name.is_empty() {
115        return None;
116    }
117    let root = read_json_file(path)?;
118    let slices = root.get("slices").and_then(Value::as_array)?;
119    for item in slices {
120        if json_string(item, "path") == Some(slice_name) {
121            return Some(
122                json_string(item, "materialize_from_runtime_layer").map(ToOwned::to_owned),
123            );
124        }
125    }
126    Some(None)
127}
128
129/// Performs request compact JSON.
130///
131/// # Parameters
132///
133/// - `text`: Input consumed by [`crate::runtime::json_commands::request_compact_json`].
134///
135/// # Returns
136///
137/// Returns [`Some`] when [`crate::runtime::json_commands::request_compact_json`] can produce a value and [`None`] otherwise.
138///
139/// # Performance
140///
141/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_compact_json`].
142///
143/// # Examples
144///
145/// ```rust,ignore
146/// let _result = pharos_native::runtime::json_commands::request_compact_json("{}");
147/// ```
148///
149/// # Related
150///
151/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
152pub fn request_compact_json(text: &str) -> Option<String> {
153    serde_json::from_str::<Value>(text)
154        .ok()
155        .and_then(|value| serde_json::to_string(&value).ok())
156}
157
158/// Performs request compact object.
159///
160/// # Parameters
161///
162/// - `text`: Input consumed by [`crate::runtime::json_commands::request_compact_object`].
163///
164/// # Returns
165///
166/// Returns the computed value produced by [`crate::runtime::json_commands::request_compact_object`].
167///
168/// # Performance
169///
170/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_compact_object`].
171///
172/// # Examples
173///
174/// ```rust,ignore
175/// let _result = pharos_native::runtime::json_commands::request_compact_object("{}");
176/// ```
177///
178/// # Related
179///
180/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
181pub fn request_compact_object(text: &str) -> String {
182    match serde_json::from_str::<Value>(text) {
183        Ok(value) if value.is_object() => {
184            serde_json::to_string(&value).unwrap_or_else(|_| "{}".to_owned())
185        }
186        _ => "{}".to_owned(),
187    }
188}
189
190/// Performs request compact object strict.
191///
192/// # Parameters
193///
194/// - `text`: Input consumed by [`crate::runtime::json_commands::request_compact_object_strict`].
195///
196/// # Returns
197///
198/// Returns [`Some`] when [`crate::runtime::json_commands::request_compact_object_strict`] can produce a value and [`None`] otherwise.
199///
200/// # Performance
201///
202/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_compact_object_strict`].
203///
204/// # Examples
205///
206/// ```rust,ignore
207/// let _result = pharos_native::runtime::json_commands::request_compact_object_strict("{}");
208/// ```
209///
210/// # Related
211///
212/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
213pub fn request_compact_object_strict(text: &str) -> Option<String> {
214    let value = serde_json::from_str::<Value>(text).ok()?;
215    value
216        .is_object()
217        .then(|| serde_json::to_string(&value).ok())
218        .flatten()
219}
220
221/// Performs request field.
222///
223/// # Parameters
224///
225/// - `text`: Input consumed by [`crate::runtime::json_commands::request_field`].
226/// - `field`: Input consumed by [`crate::runtime::json_commands::request_field`].
227///
228/// # Returns
229///
230/// Returns [`Some`] when [`crate::runtime::json_commands::request_field`] can produce a value and [`None`] otherwise.
231///
232/// # Performance
233///
234/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_field`].
235///
236/// # Examples
237///
238/// ```rust,ignore
239/// let _result = pharos_native::runtime::json_commands::request_field("{}", "field");
240/// ```
241///
242/// # Related
243///
244/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
245pub fn request_field(text: &str, field: &str) -> Option<String> {
246    if field.is_empty() {
247        return None;
248    }
249    serde_json::from_str::<Value>(text)
250        .ok()?
251        .as_object()?
252        .get(field)?
253        .as_str()
254        .map(ToOwned::to_owned)
255}
256
257/// Performs manifest fixture path raw.
258///
259/// # Parameters
260///
261/// - `path`: Input consumed by [`crate::runtime::json_commands::manifest_fixture_path_raw`].
262/// - `key`: Input consumed by [`crate::runtime::json_commands::manifest_fixture_path_raw`].
263///
264/// # Returns
265///
266/// Returns [`Some`] when [`crate::runtime::json_commands::manifest_fixture_path_raw`] can produce a value and [`None`] otherwise.
267///
268/// # Examples
269///
270/// ```rust,ignore
271/// let _result = pharos_native::runtime::json_commands::manifest_fixture_path_raw(std::path::Path::new("fixture.json"), "key");
272/// ```
273///
274/// # Related
275///
276/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
277pub fn manifest_fixture_path_raw(path: &Path, key: &str) -> Option<String> {
278    if key.is_empty() {
279        return None;
280    }
281    let root = read_json_file(path)?;
282    json_string(&root, key)
283        .or_else(|| {
284            root.get("fixtures")
285                .and_then(|value| json_string(value, key))
286        })
287        .or_else(|| {
288            root.get("database")
289                .and_then(|value| json_string(value, key))
290        })
291        .map(ToOwned::to_owned)
292}
293
294/// Performs manifest app root.
295///
296/// # Parameters
297///
298/// - `path`: Input consumed by [`crate::runtime::json_commands::manifest_app_root`].
299///
300/// # Returns
301///
302/// Returns [`Some`] when [`crate::runtime::json_commands::manifest_app_root`] can produce a value and [`None`] otherwise.
303///
304/// # Examples
305///
306/// ```rust,ignore
307/// let _result = pharos_native::runtime::json_commands::manifest_app_root(std::path::Path::new("fixture.json"));
308/// ```
309///
310/// # Related
311///
312/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
313pub fn manifest_app_root(path: &Path) -> Option<String> {
314    json_string(&read_json_file(path)?, "app_root").map(ToOwned::to_owned)
315}
316
317/// Performs URL decode component.
318fn url_decode_component(text: &str) -> Option<String> {
319    let bytes = text.as_bytes();
320    let mut out = Vec::with_capacity(text.len());
321    let mut index = 0usize;
322    while index < bytes.len() {
323        match bytes[index] {
324            b'+' => {
325                out.push(b' ');
326                index += 1;
327            }
328            b'%' if index + 2 < bytes.len() => {
329                let hex = std::str::from_utf8(&bytes[index + 1..index + 3]).ok()?;
330                let value = u8::from_str_radix(hex, 16).ok()?;
331                out.push(value);
332                index += 3;
333            }
334            b'%' => return None,
335            value => {
336                out.push(value);
337                index += 1;
338            }
339        }
340    }
341    String::from_utf8(out).ok()
342}
343
344/// Ensures percent-decoded bytes become UTF-8 once, preserving editor labels and user copy.
345#[cfg(test)]
346#[test]
347fn form_components_preserve_utf8() {
348    assert_eq!(
349        url_decode_component("action+%E2%80%94+caf%C3%A9"),
350        Some("action — café".into())
351    );
352    assert_eq!(url_decode_component("日本語"), Some("日本語".into()));
353    assert_eq!(url_decode_component("%FF"), None);
354    assert_eq!(url_decode_component("%E2%"), None);
355}
356
357/// Percent-encodes one bounded query value for safe reuse in generated links.
358pub(super) fn url_encode_query_component(value: &str) -> String {
359    const HEX: &[u8; 16] = b"0123456789ABCDEF";
360    let mut encoded = String::with_capacity(value.len());
361    for byte in value.bytes() {
362        if byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'.' | b'_' | b'~') {
363            encoded.push(char::from(byte));
364        } else {
365            encoded.push('%');
366            encoded.push(char::from(HEX[usize::from(byte >> 4)]));
367            encoded.push(char::from(HEX[usize::from(byte & 0x0f)]));
368        }
369    }
370    encoded
371}
372
373/// Performs request query value.
374///
375/// # Parameters
376///
377/// - `query`: Input consumed by [`crate::runtime::json_commands::request_query_value`].
378/// - `key`: Input consumed by [`crate::runtime::json_commands::request_query_value`].
379///
380/// # Returns
381///
382/// Returns [`Some`] when [`crate::runtime::json_commands::request_query_value`] can produce a value and [`None`] otherwise.
383///
384/// # Performance
385///
386/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_query_value`].
387///
388/// # Examples
389///
390/// ```rust,ignore
391/// let _result = pharos_native::runtime::json_commands::request_query_value("page=1", "key");
392/// ```
393///
394/// # Related
395///
396/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
397pub fn request_query_value(query: &str, key: &str) -> Option<String> {
398    if key.is_empty() {
399        return None;
400    }
401    for pair in query.split('&') {
402        let (raw_key, raw_value) = pair.split_once('=').unwrap_or((pair, ""));
403        if url_decode_component(raw_key).as_deref() == Some(key) {
404            return url_decode_component(raw_value);
405        }
406    }
407    None
408}
409
410/// Performs request form value.
411///
412/// # Parameters
413///
414/// - `form_body`: Input consumed by [`crate::runtime::json_commands::request_form_value`].
415/// - `key`: Input consumed by [`crate::runtime::json_commands::request_form_value`].
416///
417/// # Returns
418///
419/// Returns [`Some`] when [`crate::runtime::json_commands::request_form_value`] can produce a value and [`None`] otherwise.
420///
421/// # Examples
422///
423/// ```rust,ignore
424/// let _result = pharos_native::runtime::json_commands::request_form_value("name=value", "key");
425/// ```
426///
427/// # Related
428///
429/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
430pub fn request_form_value(form_body: &str, key: &str) -> Option<String> {
431    request_query_value(form_body, key)
432}
433
434/// Performs multipart boundary.
435fn multipart_boundary(content_type: &str) -> Option<String> {
436    let boundary_start = content_type.find("boundary=")? + 9;
437    let suffix = &content_type[boundary_start..];
438    if let Some(stripped) = suffix.strip_prefix('"') {
439        let end = stripped.find('"')?;
440        return Some(stripped[..end].to_owned());
441    }
442    let end = suffix
443        .find(|ch: char| ch == ';' || ch.is_ascii_whitespace())
444        .unwrap_or(suffix.len());
445    (end > 0).then(|| suffix[..end].to_owned())
446}
447
448/// Finds bytes.
449fn find_bytes(haystack: &[u8], needle: &[u8], start: usize) -> Option<usize> {
450    if needle.is_empty() || haystack.len() < needle.len() || start >= haystack.len() {
451        return None;
452    }
453    haystack[start..]
454        .windows(needle.len())
455        .position(|window| window == needle)
456        .map(|offset| start + offset)
457}
458
459/// Performs multipart header param.
460fn multipart_header_param(headers_text: &str, key: &str) -> Option<String> {
461    let pattern = format!("{key}=\"");
462    let match_index = headers_text.find(&pattern)? + pattern.len();
463    let suffix = &headers_text[match_index..];
464    let end = suffix.find('"')?;
465    Some(suffix[..end].to_owned())
466}
467
468/// Performs multipart find part from body.
469fn multipart_parts_from_body(
470    body: &[u8],
471    content_type: &str,
472    field_name: &str,
473    max_parts: usize,
474    max_total_bytes: usize,
475) -> Vec<MultipartPart> {
476    if body.is_empty() || field_name.is_empty() || max_parts == 0 {
477        return Vec::new();
478    }
479
480    let Some(boundary) = multipart_boundary(content_type) else {
481        return Vec::new();
482    };
483    if boundary.is_empty() {
484        return Vec::new();
485    }
486
487    let delimiter = format!("--{boundary}").into_bytes();
488    let delimiter_lf = format!("\n--{boundary}").into_bytes();
489    let Some(mut cursor) = find_bytes(body, &delimiter, 0) else {
490        return Vec::new();
491    };
492    let mut parts = Vec::new();
493    let mut total_bytes = 0usize;
494    let mut scanned_parts = 0usize;
495
496    while cursor + delimiter.len() <= body.len() {
497        scanned_parts += 1;
498        if scanned_parts > 1024 {
499            return Vec::new();
500        }
501        let mut part_cursor = cursor + delimiter.len();
502        if part_cursor + 2 <= body.len()
503            && body[part_cursor] == b'-'
504            && body[part_cursor + 1] == b'-'
505        {
506            break;
507        }
508        if part_cursor + 2 <= body.len()
509            && body[part_cursor] == b'\r'
510            && body[part_cursor + 1] == b'\n'
511        {
512            part_cursor += 2;
513        } else if part_cursor < body.len() && body[part_cursor] == b'\n' {
514            part_cursor += 1;
515        }
516
517        // Header searches must not rescan the remaining file payload for each part.
518        let header_limit = body.len().min(part_cursor.saturating_add(16 * 1024));
519        let next_crlf = find_bytes(&body[..header_limit], b"\r\n\r\n", part_cursor);
520        let next_lf = find_bytes(&body[..header_limit], b"\n\n", part_cursor);
521        let (header_end, header_sep_len) = match (next_crlf, next_lf) {
522            (Some(crlf), Some(lf)) if crlf <= lf => (crlf, 4usize),
523            (Some(crlf), None) => (crlf, 4usize),
524            (None, Some(lf)) => (lf, 2usize),
525            _ => break,
526        };
527
528        let headers_text = String::from_utf8_lossy(&body[part_cursor..header_end]).into_owned();
529        let part_name = multipart_header_param(&headers_text, "name");
530        let filename = multipart_header_param(&headers_text, "filename");
531        let content_start = header_end + header_sep_len;
532
533        let next_marker = find_bytes(body, &delimiter_lf, content_start)
534            .map(|marker| {
535                if marker > content_start && body[marker - 1] == b'\r' {
536                    marker - 1
537                } else {
538                    marker
539                }
540            })
541            .unwrap_or(body.len());
542
543        if part_name.as_deref() == Some(field_name) || field_name == "*" {
544            let content = body[content_start..next_marker].to_vec();
545            total_bytes = total_bytes.saturating_add(content.len());
546            if parts.len() >= max_parts || total_bytes > max_total_bytes {
547                return Vec::new();
548            }
549            let text = String::from_utf8(content.clone()).ok();
550            parts.push(MultipartPart {
551                name: part_name.unwrap_or_default(),
552                text,
553                filename,
554                content,
555            });
556        }
557
558        if next_marker >= body.len() {
559            break;
560        }
561        cursor = if body[next_marker] == b'\r' {
562            next_marker + 2
563        } else {
564            next_marker + 1
565        };
566        let Some(next_cursor) = find_bytes(body, &delimiter, cursor) else {
567            break;
568        };
569        cursor = next_cursor;
570    }
571
572    parts
573}
574
575/// Parses bounded named parts for declared multipart actions using the shared parser.
576pub(super) fn request_multipart_named_parts(
577    content_type: &str,
578    body: &[u8],
579    max_parts: usize,
580    max_bytes: usize,
581) -> Vec<(String, Option<String>, Vec<u8>)> {
582    multipart_parts_from_body(body, content_type, "*", max_parts, max_bytes)
583        .into_iter()
584        .map(|part| (part.name, part.filename, part.content))
585        .collect()
586}
587
588fn multipart_find_part_from_body(
589    body: &[u8],
590    content_type: &str,
591    field_name: &str,
592) -> Option<MultipartPart> {
593    multipart_parts_from_body(body, content_type, field_name, 1, body.len())
594        .into_iter()
595        .next()
596}
597
598/// Extracts one text field from an in-memory multipart request body.
599///
600/// # Parameters
601///
602/// - `content_type`: Input consumed by [`crate::runtime::json_commands::request_multipart_field_value`].
603/// - `body`: Input consumed by [`crate::runtime::json_commands::request_multipart_field_value`].
604/// - `field_name`: Input consumed by [`crate::runtime::json_commands::request_multipart_field_value`].
605///
606/// # Returns
607///
608/// Returns [`Some`] when [`crate::runtime::json_commands::request_multipart_field_value`] can produce a value and [`None`] otherwise.
609///
610/// # Examples
611///
612/// ```rust,ignore
613/// let _result = pharos_native::runtime::json_commands::request_multipart_field_value(todo!(), b"", todo!());
614/// ```
615///
616/// # Related
617///
618/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
619pub fn request_multipart_field_value(
620    content_type: &str,
621    body: &[u8],
622    field_name: &str,
623) -> Option<String> {
624    multipart_find_part_from_body(body, content_type, field_name).and_then(|part| part.text)
625}
626
627/// Extracts all uploaded files for one multipart field from an in-memory request body.
628pub fn request_multipart_file_parts(
629    content_type: &str,
630    body: &[u8],
631    field_name: &str,
632    max_parts: usize,
633    max_total_bytes: usize,
634) -> Vec<MultipartFilePart> {
635    multipart_uploaded_file_parts(
636        content_type,
637        body,
638        field_name,
639        max_parts,
640        max_total_bytes,
641        false,
642    )
643}
644
645/// Extracts bounded source uploads while preserving legitimate empty source files.
646pub fn request_multipart_source_file_parts(
647    content_type: &str,
648    body: &[u8],
649    field_name: &str,
650    max_parts: usize,
651    max_total_bytes: usize,
652) -> Vec<MultipartFilePart> {
653    multipart_uploaded_file_parts(
654        content_type,
655        body,
656        field_name,
657        max_parts,
658        max_total_bytes,
659        true,
660    )
661}
662
663/// Applies filename validation and the caller's empty-file policy to bounded multipart parts.
664fn multipart_uploaded_file_parts(
665    content_type: &str,
666    body: &[u8],
667    field_name: &str,
668    max_parts: usize,
669    max_total_bytes: usize,
670    allow_empty: bool,
671) -> Vec<MultipartFilePart> {
672    multipart_parts_from_body(body, content_type, field_name, max_parts, max_total_bytes)
673        .into_iter()
674        .filter_map(|part| {
675            let filename = part.filename?;
676            (!filename.trim().is_empty() && (allow_empty || !part.content.is_empty())).then_some(
677                MultipartFilePart {
678                    filename,
679                    content: part.content,
680                },
681            )
682        })
683        .collect()
684}
685
686/// Performs request form field value.
687///
688/// # Parameters
689///
690/// - `content_type`: Input consumed by [`crate::runtime::json_commands::request_form_field_value`].
691/// - `form_body`: Input consumed by [`crate::runtime::json_commands::request_form_field_value`].
692/// - `body_path`: Input consumed by [`crate::runtime::json_commands::request_form_field_value`].
693/// - `field_name`: Input consumed by [`crate::runtime::json_commands::request_form_field_value`].
694///
695/// # Returns
696///
697/// Returns [`Some`] when [`crate::runtime::json_commands::request_form_field_value`] can produce a value and [`None`] otherwise.
698///
699/// # Performance
700///
701/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_form_field_value`].
702///
703/// # Examples
704///
705/// ```rust,ignore
706/// let _result = pharos_native::runtime::json_commands::request_form_field_value(todo!(), "name=value", todo!(), todo!());
707/// ```
708///
709/// # Related
710///
711/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
712pub fn request_form_field_value(
713    content_type: Option<&str>,
714    form_body: Option<&str>,
715    body_path: Option<&Path>,
716    field_name: &str,
717) -> Option<String> {
718    if field_name.is_empty() {
719        return None;
720    }
721    if content_type.is_some_and(|value| value.starts_with("multipart/form-data")) {
722        let body = fs::read(body_path?).ok()?;
723        return multipart_find_part_from_body(&body, content_type?, field_name)
724            .and_then(|part| part.text);
725    }
726
727    let raw_form = if let Some(path) = body_path.filter(|path| path.exists()) {
728        fs::read_to_string(path)
729            .ok()
730            .unwrap_or_else(|| form_body.unwrap_or("").to_owned())
731    } else {
732        form_body.unwrap_or("").to_owned()
733    };
734    if content_type.is_some_and(|value| value.starts_with("application/json")) {
735        return serde_json::from_str::<Value>(&raw_form)
736            .ok()
737            .and_then(|value| value.as_object().cloned())
738            .and_then(|object| object.get(field_name).cloned())
739            .and_then(|value| match value {
740                Value::String(value) => Some(value),
741                Value::Number(value) => Some(value.to_string()),
742                Value::Bool(value) => Some(value.to_string()),
743                Value::Null => None,
744                _ => None,
745            });
746    }
747    request_query_value(&raw_form, field_name)
748}
749
750/// Performs dynamic multipart filename.
751///
752/// # Parameters
753///
754/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_filename`].
755/// - `body_path`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_filename`].
756/// - `field_name`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_filename`].
757///
758/// # Returns
759///
760/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_multipart_filename`] can produce a value and [`None`] otherwise.
761///
762/// # Examples
763///
764/// ```rust,ignore
765/// let _result = pharos_native::runtime::json_commands::dynamic_multipart_filename(todo!(), todo!(), todo!());
766/// ```
767///
768/// # Related
769///
770/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
771pub fn dynamic_multipart_filename(
772    content_type: &str,
773    body_path: &Path,
774    field_name: &str,
775) -> Option<String> {
776    multipart_find_part_from_body(&fs::read(body_path).ok()?, content_type, field_name)?.filename
777}
778
779/// Performs dynamic multipart extract text.
780///
781/// # Parameters
782///
783/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_text`].
784/// - `body_path`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_text`].
785/// - `field_name`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_text`].
786///
787/// # Returns
788///
789/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_multipart_extract_text`] can produce a value and [`None`] otherwise.
790///
791/// # Examples
792///
793/// ```rust,ignore
794/// let _result = pharos_native::runtime::json_commands::dynamic_multipart_extract_text(todo!(), todo!(), todo!());
795/// ```
796///
797/// # Related
798///
799/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
800pub fn dynamic_multipart_extract_text(
801    content_type: &str,
802    body_path: &Path,
803    field_name: &str,
804) -> Option<String> {
805    multipart_find_part_from_body(&fs::read(body_path).ok()?, content_type, field_name)?.text
806}
807
808/// Performs dynamic multipart extract file.
809///
810/// # Parameters
811///
812/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_file`].
813/// - `body_path`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_file`].
814/// - `field_name`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_file`].
815/// - `output_path`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_extract_file`].
816///
817/// # Returns
818///
819/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_multipart_extract_file`].
820///
821/// # Examples
822///
823/// ```rust,ignore
824/// let _result = pharos_native::runtime::json_commands::dynamic_multipart_extract_file(todo!(), todo!(), todo!(), todo!());
825/// ```
826///
827/// # Related
828///
829/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
830pub fn dynamic_multipart_extract_file(
831    content_type: &str,
832    body_path: &Path,
833    field_name: &str,
834    output_path: &Path,
835) -> i32 {
836    if output_path.as_os_str().is_empty() {
837        return 64;
838    }
839    let Some(part) = fs::read(body_path)
840        .ok()
841        .and_then(|body| multipart_find_part_from_body(&body, content_type, field_name))
842    else {
843        return 1;
844    };
845    if part.content.is_empty() {
846        return 1;
847    }
848    super::fs::write_binary_file(output_path, &part.content, 0o640)
849        .map(|_| 0)
850        .unwrap_or(73)
851}
852
853/// Performs request booking options JSON from form.
854///
855/// # Parameters
856///
857/// - `content_type`: Input consumed by [`crate::runtime::json_commands::request_booking_options_json_from_form`].
858/// - `form_body`: Input consumed by [`crate::runtime::json_commands::request_booking_options_json_from_form`].
859/// - `body_path`: Input consumed by [`crate::runtime::json_commands::request_booking_options_json_from_form`].
860///
861/// # Returns
862///
863/// Returns [`Some`] when [`crate::runtime::json_commands::request_booking_options_json_from_form`] can produce a value and [`None`] otherwise.
864///
865/// # Performance
866///
867/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_booking_options_json_from_form`].
868///
869/// # Examples
870///
871/// ```rust,ignore
872/// let _result = pharos_native::runtime::json_commands::request_booking_options_json_from_form(todo!(), "name=value", todo!());
873/// ```
874///
875/// # Related
876///
877/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
878pub fn request_booking_options_json_from_form(
879    content_type: Option<&str>,
880    form_body: Option<&str>,
881    body_path: Option<&Path>,
882) -> Option<String> {
883    let count_value =
884        request_form_field_value(content_type, form_body, body_path, "booking_option_count")
885            .filter(|value| value.chars().all(|ch| ch.is_ascii_digit()))
886            .and_then(|value| value.parse::<usize>().ok())
887            .map(|value| value.min(64))
888            .unwrap_or(0);
889
890    let mut raw_lines = Vec::new();
891    if count_value > 0 {
892        for index in 1..=count_value {
893            let label = request_form_field_value(
894                content_type,
895                form_body,
896                body_path,
897                &format!("booking_option_label_{index}"),
898            )
899            .unwrap_or_default();
900            let duration = request_form_field_value(
901                content_type,
902                form_body,
903                body_path,
904                &format!("booking_option_duration_{index}"),
905            )
906            .unwrap_or_default();
907            let cost = request_form_field_value(
908                content_type,
909                form_body,
910                body_path,
911                &format!("booking_option_cost_{index}"),
912            )
913            .unwrap_or_default();
914            if !(label.is_empty() && duration.is_empty() && cost.is_empty()) {
915                raw_lines.push(format!("{label}|{duration}|{cost}"));
916            }
917        }
918    }
919    if raw_lines.is_empty()
920        && let Some(raw) =
921            request_form_field_value(content_type, form_body, body_path, "booking_options")
922        && !raw.is_empty()
923    {
924        raw_lines = raw.lines().map(ToOwned::to_owned).collect();
925    }
926    if raw_lines.is_empty() {
927        return Some("[]".to_owned());
928    }
929
930    let mut rows = Vec::new();
931    for line in raw_lines {
932        let mut parts = line.splitn(3, '|');
933        let label = parts.next().unwrap_or_default();
934        let duration_text = parts.next().unwrap_or_default();
935        let cost = parts.next().unwrap_or_default();
936        if label.is_empty() && duration_text.is_empty() && cost.is_empty() {
937            continue;
938        }
939        let duration = if duration_text.chars().all(|ch| ch.is_ascii_digit()) {
940            duration_text.parse::<u64>().ok().unwrap_or(0)
941        } else {
942            0
943        };
944        rows.push(serde_json::json!({
945            "label": label,
946            "duration_minutes": duration,
947            "cost": cost,
948        }));
949    }
950    serde_json::to_string(&rows).ok()
951}
952
953/// Performs request cookie value.
954///
955/// # Parameters
956///
957/// - `cookie_header`: Input consumed by [`crate::runtime::json_commands::request_cookie_value`].
958/// - `name`: Input consumed by [`crate::runtime::json_commands::request_cookie_value`].
959///
960/// # Returns
961///
962/// Returns [`Some`] when [`crate::runtime::json_commands::request_cookie_value`] can produce a value and [`None`] otherwise.
963///
964/// # Performance
965///
966/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_cookie_value`].
967///
968/// # Examples
969///
970/// ```rust,ignore
971/// let _result = pharos_native::runtime::json_commands::request_cookie_value("session=abc", "name");
972/// ```
973///
974/// # Related
975///
976/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
977pub fn request_cookie_value(cookie_header: &str, name: &str) -> Option<String> {
978    if name.is_empty() {
979        return None;
980    }
981    for segment in cookie_header.split(';') {
982        let (key, value) = segment.trim().split_once('=')?;
983        if key.trim() == name {
984            return Some(value.trim().to_owned());
985        }
986    }
987    None
988}
989
990/// Handles bundle manifest slice order command.
991///
992/// # Parameters
993///
994/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_bundle_manifest_slice_order_command`].
995///
996/// # Returns
997///
998/// Returns [`Some`] when [`crate::runtime::json_commands::handle_bundle_manifest_slice_order_command`] can produce a value and [`None`] otherwise.
999///
1000/// # Examples
1001///
1002/// ```rust,ignore
1003/// let _result = pharos_native::runtime::json_commands::handle_bundle_manifest_slice_order_command(std::path::Path::new("fixture.json"));
1004/// ```
1005///
1006/// # Related
1007///
1008/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1009pub fn handle_bundle_manifest_slice_order_command(path: &Path) -> Option<String> {
1010    bundle_manifest_slice_order_lines(path).map(|lines| lines.join("\n"))
1011}
1012
1013/// Handles bundle manifest layer for slice command.
1014///
1015/// # Parameters
1016///
1017/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_bundle_manifest_layer_for_slice_command`].
1018/// - `slice_name`: Input consumed by [`crate::runtime::json_commands::handle_bundle_manifest_layer_for_slice_command`].
1019///
1020/// # Returns
1021///
1022/// Returns [`Some`] when [`crate::runtime::json_commands::handle_bundle_manifest_layer_for_slice_command`] can produce a value and [`None`] otherwise.
1023///
1024/// # Examples
1025///
1026/// ```rust,ignore
1027/// let _result = pharos_native::runtime::json_commands::handle_bundle_manifest_layer_for_slice_command(std::path::Path::new("fixture.json"), "slice");
1028/// ```
1029///
1030/// # Related
1031///
1032/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1033pub fn handle_bundle_manifest_layer_for_slice_command(
1034    path: &Path,
1035    slice_name: &str,
1036) -> Option<String> {
1037    bundle_manifest_layer_for_slice(path, slice_name).flatten()
1038}
1039
1040/// Handles request query value command.
1041///
1042/// # Parameters
1043///
1044/// - `query`: Input consumed by [`crate::runtime::json_commands::handle_request_query_value_command`].
1045/// - `key`: Input consumed by [`crate::runtime::json_commands::handle_request_query_value_command`].
1046///
1047/// # Returns
1048///
1049/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_query_value_command`] can produce a value and [`None`] otherwise.
1050///
1051/// # Examples
1052///
1053/// ```rust,ignore
1054/// let _result = pharos_native::runtime::json_commands::handle_request_query_value_command("page=1", "key");
1055/// ```
1056///
1057/// # Related
1058///
1059/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1060pub fn handle_request_query_value_command(query: &str, key: &str) -> Option<String> {
1061    request_query_value(query, key)
1062}
1063
1064/// Handles request form value command.
1065///
1066/// # Parameters
1067///
1068/// - `form_body`: Input consumed by [`crate::runtime::json_commands::handle_request_form_value_command`].
1069/// - `key`: Input consumed by [`crate::runtime::json_commands::handle_request_form_value_command`].
1070///
1071/// # Returns
1072///
1073/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_form_value_command`] can produce a value and [`None`] otherwise.
1074///
1075/// # Examples
1076///
1077/// ```rust,ignore
1078/// let _result = pharos_native::runtime::json_commands::handle_request_form_value_command("name=value", "key");
1079/// ```
1080///
1081/// # Related
1082///
1083/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1084pub fn handle_request_form_value_command(form_body: &str, key: &str) -> Option<String> {
1085    request_form_value(form_body, key)
1086}
1087
1088/// Handles request form field command.
1089///
1090/// # Parameters
1091///
1092/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_request_form_field_command`].
1093/// - `form_body`: Input consumed by [`crate::runtime::json_commands::handle_request_form_field_command`].
1094/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_request_form_field_command`].
1095/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_request_form_field_command`].
1096///
1097/// # Returns
1098///
1099/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_form_field_command`] can produce a value and [`None`] otherwise.
1100///
1101/// # Examples
1102///
1103/// ```rust,ignore
1104/// let _result = pharos_native::runtime::json_commands::handle_request_form_field_command(todo!(), "name=value", todo!(), todo!());
1105/// ```
1106///
1107/// # Related
1108///
1109/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1110pub fn handle_request_form_field_command(
1111    content_type: Option<&str>,
1112    form_body: Option<&str>,
1113    body_path: Option<&Path>,
1114    field_name: &str,
1115) -> Option<String> {
1116    request_form_field_value(content_type, form_body, body_path, field_name)
1117}
1118
1119/// Handles request cookie value command.
1120///
1121/// # Parameters
1122///
1123/// - `cookie_header`: Input consumed by [`crate::runtime::json_commands::handle_request_cookie_value_command`].
1124/// - `name`: Input consumed by [`crate::runtime::json_commands::handle_request_cookie_value_command`].
1125///
1126/// # Returns
1127///
1128/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_cookie_value_command`] can produce a value and [`None`] otherwise.
1129///
1130/// # Examples
1131///
1132/// ```rust,ignore
1133/// let _result = pharos_native::runtime::json_commands::handle_request_cookie_value_command("session=abc", "name");
1134/// ```
1135///
1136/// # Related
1137///
1138/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1139pub fn handle_request_cookie_value_command(cookie_header: &str, name: &str) -> Option<String> {
1140    request_cookie_value(cookie_header, name)
1141}
1142
1143/// Handles dynamic multipart filename command.
1144///
1145/// # Parameters
1146///
1147/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_filename_command`].
1148/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_filename_command`].
1149/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_filename_command`].
1150///
1151/// # Returns
1152///
1153/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_multipart_filename_command`] can produce a value and [`None`] otherwise.
1154///
1155/// # Examples
1156///
1157/// ```rust,ignore
1158/// let _result = pharos_native::runtime::json_commands::handle_dynamic_multipart_filename_command(todo!(), todo!(), todo!());
1159/// ```
1160///
1161/// # Related
1162///
1163/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1164pub fn handle_dynamic_multipart_filename_command(
1165    content_type: &str,
1166    body_path: &Path,
1167    field_name: &str,
1168) -> Option<String> {
1169    dynamic_multipart_filename(content_type, body_path, field_name)
1170}
1171
1172/// Handles dynamic multipart extract text command.
1173///
1174/// # Parameters
1175///
1176/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_text_command`].
1177/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_text_command`].
1178/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_text_command`].
1179///
1180/// # Returns
1181///
1182/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_multipart_extract_text_command`] can produce a value and [`None`] otherwise.
1183///
1184/// # Examples
1185///
1186/// ```rust,ignore
1187/// let _result = pharos_native::runtime::json_commands::handle_dynamic_multipart_extract_text_command(todo!(), todo!(), todo!());
1188/// ```
1189///
1190/// # Related
1191///
1192/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1193pub fn handle_dynamic_multipart_extract_text_command(
1194    content_type: &str,
1195    body_path: &Path,
1196    field_name: &str,
1197) -> Option<String> {
1198    dynamic_multipart_extract_text(content_type, body_path, field_name)
1199}
1200
1201/// Handles dynamic multipart extract file command.
1202///
1203/// # Parameters
1204///
1205/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_file_command`].
1206/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_file_command`].
1207/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_file_command`].
1208/// - `output_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_file_command`].
1209///
1210/// # Returns
1211///
1212/// Returns the computed value produced by [`crate::runtime::json_commands::handle_dynamic_multipart_extract_file_command`].
1213///
1214/// # Examples
1215///
1216/// ```rust,ignore
1217/// let _result = pharos_native::runtime::json_commands::handle_dynamic_multipart_extract_file_command(todo!(), todo!(), todo!(), todo!());
1218/// ```
1219///
1220/// # Related
1221///
1222/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1223pub fn handle_dynamic_multipart_extract_file_command(
1224    content_type: &str,
1225    body_path: &Path,
1226    field_name: &str,
1227    output_path: &Path,
1228) -> i32 {
1229    dynamic_multipart_extract_file(content_type, body_path, field_name, output_path)
1230}
1231
1232/// Handles request booking options JSON from form command.
1233///
1234/// # Parameters
1235///
1236/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_request_booking_options_json_from_form_command`].
1237/// - `form_body`: Input consumed by [`crate::runtime::json_commands::handle_request_booking_options_json_from_form_command`].
1238/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_request_booking_options_json_from_form_command`].
1239///
1240/// # Returns
1241///
1242/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_booking_options_json_from_form_command`] can produce a value and [`None`] otherwise.
1243///
1244/// # Examples
1245///
1246/// ```rust,ignore
1247/// let _result = pharos_native::runtime::json_commands::handle_request_booking_options_json_from_form_command(todo!(), "name=value", todo!());
1248/// ```
1249///
1250/// # Related
1251///
1252/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1253pub fn handle_request_booking_options_json_from_form_command(
1254    content_type: Option<&str>,
1255    form_body: Option<&str>,
1256    body_path: Option<&Path>,
1257) -> Option<String> {
1258    request_booking_options_json_from_form(content_type, form_body, body_path)
1259}
1260
1261/// Handles request compact JSON command.
1262///
1263/// # Parameters
1264///
1265/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_compact_json_command`].
1266///
1267/// # Returns
1268///
1269/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_compact_json_command`] can produce a value and [`None`] otherwise.
1270///
1271/// # Examples
1272///
1273/// ```rust,ignore
1274/// let _result = pharos_native::runtime::json_commands::handle_request_compact_json_command("{}");
1275/// ```
1276///
1277/// # Related
1278///
1279/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1280pub fn handle_request_compact_json_command(text: &str) -> Option<String> {
1281    request_compact_json(text)
1282}
1283
1284/// Handles request compact object command.
1285///
1286/// # Parameters
1287///
1288/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_compact_object_command`].
1289///
1290/// # Returns
1291///
1292/// Returns the computed value produced by [`crate::runtime::json_commands::handle_request_compact_object_command`].
1293///
1294/// # Examples
1295///
1296/// ```rust,ignore
1297/// let _result = pharos_native::runtime::json_commands::handle_request_compact_object_command("{}");
1298/// ```
1299///
1300/// # Related
1301///
1302/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1303pub fn handle_request_compact_object_command(text: &str) -> String {
1304    request_compact_object(text)
1305}
1306
1307/// Handles request compact object strict command.
1308///
1309/// # Parameters
1310///
1311/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_compact_object_strict_command`].
1312///
1313/// # Returns
1314///
1315/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_compact_object_strict_command`] can produce a value and [`None`] otherwise.
1316///
1317/// # Examples
1318///
1319/// ```rust,ignore
1320/// let _result = pharos_native::runtime::json_commands::handle_request_compact_object_strict_command("{}");
1321/// ```
1322///
1323/// # Related
1324///
1325/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1326pub fn handle_request_compact_object_strict_command(text: &str) -> Option<String> {
1327    request_compact_object_strict(text)
1328}
1329
1330/// Handles request field command.
1331///
1332/// # Parameters
1333///
1334/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_field_command`].
1335/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_request_field_command`].
1336///
1337/// # Returns
1338///
1339/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_field_command`] can produce a value and [`None`] otherwise.
1340///
1341/// # Examples
1342///
1343/// ```rust,ignore
1344/// let _result = pharos_native::runtime::json_commands::handle_request_field_command("{}", "field");
1345/// ```
1346///
1347/// # Related
1348///
1349/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1350pub fn handle_request_field_command(text: &str, field: &str) -> Option<String> {
1351    request_field(text, field)
1352}
1353
1354/// Handles manifest fixture path raw command.
1355///
1356/// # Parameters
1357///
1358/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_manifest_fixture_path_raw_command`].
1359/// - `key`: Input consumed by [`crate::runtime::json_commands::handle_manifest_fixture_path_raw_command`].
1360///
1361/// # Returns
1362///
1363/// Returns [`Some`] when [`crate::runtime::json_commands::handle_manifest_fixture_path_raw_command`] can produce a value and [`None`] otherwise.
1364///
1365/// # Examples
1366///
1367/// ```rust,ignore
1368/// let _result = pharos_native::runtime::json_commands::handle_manifest_fixture_path_raw_command(std::path::Path::new("fixture.json"), "key");
1369/// ```
1370///
1371/// # Related
1372///
1373/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1374pub fn handle_manifest_fixture_path_raw_command(path: &Path, key: &str) -> Option<String> {
1375    manifest_fixture_path_raw(path, key)
1376}
1377
1378/// Handles manifest app root command.
1379///
1380/// # Parameters
1381///
1382/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_manifest_app_root_command`].
1383///
1384/// # Returns
1385///
1386/// Returns [`Some`] when [`crate::runtime::json_commands::handle_manifest_app_root_command`] can produce a value and [`None`] otherwise.
1387///
1388/// # Examples
1389///
1390/// ```rust,ignore
1391/// let _result = pharos_native::runtime::json_commands::handle_manifest_app_root_command(std::path::Path::new("fixture.json"));
1392/// ```
1393///
1394/// # Related
1395///
1396/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1397pub fn handle_manifest_app_root_command(path: &Path) -> Option<String> {
1398    manifest_app_root(path)
1399}
1400
1401/// Finds form field value.
1402fn find_form_field_value<'a>(root: &'a Value, form_id: &str, field_id: &str) -> Option<&'a Value> {
1403    let forms = root.get("forms")?.as_array()?;
1404    for form in forms {
1405        if json_string(form, "form_id") != Some(form_id) {
1406            continue;
1407        }
1408        let fields = form.get("fields")?.as_array()?;
1409        for field in fields {
1410            if json_string(field, "field_id") == Some(field_id) {
1411                return Some(field);
1412            }
1413        }
1414    }
1415    None
1416}
1417
1418/// Performs form field JSON.
1419///
1420/// # Parameters
1421///
1422/// - `path`: Input consumed by [`crate::runtime::json_commands::form_field_json`].
1423/// - `form_id`: Input consumed by [`crate::runtime::json_commands::form_field_json`].
1424/// - `field_id`: Input consumed by [`crate::runtime::json_commands::form_field_json`].
1425///
1426/// # Returns
1427///
1428/// Returns [`Some`] when [`crate::runtime::json_commands::form_field_json`] can produce a value and [`None`] otherwise.
1429///
1430/// # Examples
1431///
1432/// ```rust,ignore
1433/// let _result = pharos_native::runtime::json_commands::form_field_json(std::path::Path::new("fixture.json"), "form", "field");
1434/// ```
1435///
1436/// # Related
1437///
1438/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1439pub fn form_field_json(path: &Path, form_id: &str, field_id: &str) -> Option<String> {
1440    if form_id.is_empty() || field_id.is_empty() {
1441        return None;
1442    }
1443    let root = read_json_file(path)?;
1444    serde_json::to_string(find_form_field_value(&root, form_id, field_id)?).ok()
1445}
1446
1447/// Performs form field JSON lines.
1448///
1449/// # Parameters
1450///
1451/// - `path`: Input consumed by [`crate::runtime::json_commands::form_field_json_lines`].
1452/// - `form_id`: Input consumed by [`crate::runtime::json_commands::form_field_json_lines`].
1453///
1454/// # Returns
1455///
1456/// Returns [`Some`] when [`crate::runtime::json_commands::form_field_json_lines`] can produce a value and [`None`] otherwise.
1457///
1458/// # Performance
1459///
1460/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::form_field_json_lines`].
1461///
1462/// # Examples
1463///
1464/// ```rust,ignore
1465/// let _result = pharos_native::runtime::json_commands::form_field_json_lines(std::path::Path::new("fixture.json"), "form");
1466/// ```
1467///
1468/// # Related
1469///
1470/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1471pub fn form_field_json_lines(path: &Path, form_id: &str) -> Option<Vec<String>> {
1472    if form_id.is_empty() {
1473        return None;
1474    }
1475    let root = read_json_file(path)?;
1476    let forms = root.get("forms")?.as_array()?;
1477    for form in forms {
1478        if json_string(form, "form_id") != Some(form_id) {
1479            continue;
1480        }
1481        let mut lines = Vec::new();
1482        for field in form.get("fields")?.as_array()? {
1483            lines.push(serde_json::to_string(field).ok()?);
1484        }
1485        return Some(lines);
1486    }
1487    Some(Vec::new())
1488}
1489
1490/// Performs form options csv.
1491///
1492/// # Parameters
1493///
1494/// - `path`: Input consumed by [`crate::runtime::json_commands::form_options_csv`].
1495/// - `form_id`: Input consumed by [`crate::runtime::json_commands::form_options_csv`].
1496/// - `field_id`: Input consumed by [`crate::runtime::json_commands::form_options_csv`].
1497///
1498/// # Returns
1499///
1500/// Returns [`Some`] when [`crate::runtime::json_commands::form_options_csv`] can produce a value and [`None`] otherwise.
1501///
1502/// # Performance
1503///
1504/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::form_options_csv`].
1505///
1506/// # Examples
1507///
1508/// ```rust,ignore
1509/// let _result = pharos_native::runtime::json_commands::form_options_csv(std::path::Path::new("fixture.json"), "form", "field");
1510/// ```
1511///
1512/// # Related
1513///
1514/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1515pub fn form_options_csv(path: &Path, form_id: &str, field_id: &str) -> Option<String> {
1516    if form_id.is_empty() || field_id.is_empty() {
1517        return None;
1518    }
1519    let root = read_json_file(path)?;
1520    let field = find_form_field_value(&root, form_id, field_id)?;
1521    let mut values = Vec::new();
1522    for option in field.get("options")?.as_array()? {
1523        if let Some(value) = json_string(option, "value") {
1524            values.push(value.to_owned());
1525        }
1526    }
1527    Some(values.join(","))
1528}
1529
1530/// Performs form options HTML.
1531///
1532/// # Parameters
1533///
1534/// - `app_root`: Input consumed by [`crate::runtime::json_commands::form_options_html`].
1535/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::form_options_html`].
1536/// - `form_id`: Input consumed by [`crate::runtime::json_commands::form_options_html`].
1537/// - `field_id`: Input consumed by [`crate::runtime::json_commands::form_options_html`].
1538/// - `selected`: Input consumed by [`crate::runtime::json_commands::form_options_html`].
1539///
1540/// # Returns
1541///
1542/// Returns [`Some`] when [`crate::runtime::json_commands::form_options_html`] can produce a value and [`None`] otherwise.
1543///
1544/// # Performance
1545///
1546/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::form_options_html`].
1547///
1548/// # Examples
1549///
1550/// ```rust,ignore
1551/// let _result = pharos_native::runtime::json_commands::form_options_html(std::path::Path::new("apps/dev_docs"), todo!(), "form", "field", todo!());
1552/// ```
1553///
1554/// # Related
1555///
1556/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1557pub fn form_options_html(
1558    app_root: &Path,
1559    fixture_path: &Path,
1560    form_id: &str,
1561    field_id: &str,
1562    selected: Option<&str>,
1563) -> Option<String> {
1564    if app_root.as_os_str().is_empty() || form_id.is_empty() || field_id.is_empty() {
1565        return None;
1566    }
1567    let root = read_json_file(fixture_path)?;
1568    let field = find_form_field_value(&root, form_id, field_id)?;
1569    let mut out = String::new();
1570    for option in field.get("options")?.as_array()? {
1571        let Some(value) = json_string(option, "value") else {
1572            continue;
1573        };
1574        let value = value.to_owned();
1575        let label = json_string(option, "label")
1576            .map(ToOwned::to_owned)
1577            .unwrap_or_else(|| value.clone());
1578        let params = serde_json::Map::from_iter([
1579            ("option_value".to_owned(), Value::String(value.to_string())),
1580            (
1581                "selected_attr".to_owned(),
1582                Value::String(
1583                    if selected == Some(value.as_str()) {
1584                        " selected"
1585                    } else {
1586                        Default::default()
1587                    }
1588                    .to_owned(),
1589                ),
1590            ),
1591            ("option_label".to_owned(), Value::String(label.to_string())),
1592        ]);
1593        out.push_str(
1594            &generated::render_generated_admin_fragment_from_value_runtime(
1595                app_root,
1596                "templates/shared/fragments/select_option.html",
1597                &params,
1598            )?,
1599        );
1600    }
1601    Some(out)
1602}
1603
1604/// Handles form field JSON command.
1605///
1606/// # Parameters
1607///
1608/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_form_field_json_command`].
1609/// - `form_id`: Input consumed by [`crate::runtime::json_commands::handle_form_field_json_command`].
1610/// - `field_id`: Input consumed by [`crate::runtime::json_commands::handle_form_field_json_command`].
1611///
1612/// # Returns
1613///
1614/// Returns [`Some`] when [`crate::runtime::json_commands::handle_form_field_json_command`] can produce a value and [`None`] otherwise.
1615///
1616/// # Examples
1617///
1618/// ```rust,ignore
1619/// let _result = pharos_native::runtime::json_commands::handle_form_field_json_command(std::path::Path::new("fixture.json"), "form", "field");
1620/// ```
1621///
1622/// # Related
1623///
1624/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1625pub fn handle_form_field_json_command(
1626    path: &Path,
1627    form_id: &str,
1628    field_id: &str,
1629) -> Option<String> {
1630    form_field_json(path, form_id, field_id)
1631}
1632
1633/// Handles form field JSON lines command.
1634///
1635/// # Parameters
1636///
1637/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_form_field_json_lines_command`].
1638/// - `form_id`: Input consumed by [`crate::runtime::json_commands::handle_form_field_json_lines_command`].
1639///
1640/// # Returns
1641///
1642/// Returns [`Some`] when [`crate::runtime::json_commands::handle_form_field_json_lines_command`] can produce a value and [`None`] otherwise.
1643///
1644/// # Examples
1645///
1646/// ```rust,ignore
1647/// let _result = pharos_native::runtime::json_commands::handle_form_field_json_lines_command(std::path::Path::new("fixture.json"), "form");
1648/// ```
1649///
1650/// # Related
1651///
1652/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1653pub fn handle_form_field_json_lines_command(path: &Path, form_id: &str) -> Option<String> {
1654    form_field_json_lines(path, form_id).map(|lines| lines.join("\n"))
1655}
1656
1657/// Handles form options csv command.
1658///
1659/// # Parameters
1660///
1661/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_form_options_csv_command`].
1662/// - `form_id`: Input consumed by [`crate::runtime::json_commands::handle_form_options_csv_command`].
1663/// - `field_id`: Input consumed by [`crate::runtime::json_commands::handle_form_options_csv_command`].
1664///
1665/// # Returns
1666///
1667/// Returns [`Some`] when [`crate::runtime::json_commands::handle_form_options_csv_command`] can produce a value and [`None`] otherwise.
1668///
1669/// # Examples
1670///
1671/// ```rust,ignore
1672/// let _result = pharos_native::runtime::json_commands::handle_form_options_csv_command(std::path::Path::new("fixture.json"), "form", "field");
1673/// ```
1674///
1675/// # Related
1676///
1677/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1678pub fn handle_form_options_csv_command(
1679    path: &Path,
1680    form_id: &str,
1681    field_id: &str,
1682) -> Option<String> {
1683    form_options_csv(path, form_id, field_id)
1684}
1685
1686/// Handles form options HTML command.
1687///
1688/// # Parameters
1689///
1690/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_form_options_html_command`].
1691/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::handle_form_options_html_command`].
1692/// - `form_id`: Input consumed by [`crate::runtime::json_commands::handle_form_options_html_command`].
1693/// - `field_id`: Input consumed by [`crate::runtime::json_commands::handle_form_options_html_command`].
1694/// - `selected`: Input consumed by [`crate::runtime::json_commands::handle_form_options_html_command`].
1695///
1696/// # Returns
1697///
1698/// Returns [`Some`] when [`crate::runtime::json_commands::handle_form_options_html_command`] can produce a value and [`None`] otherwise.
1699///
1700/// # Examples
1701///
1702/// ```rust,ignore
1703/// let _result = pharos_native::runtime::json_commands::handle_form_options_html_command(std::path::Path::new("apps/dev_docs"), todo!(), "form", "field", todo!());
1704/// ```
1705///
1706/// # Related
1707///
1708/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1709pub fn handle_form_options_html_command(
1710    app_root: &Path,
1711    fixture_path: &Path,
1712    form_id: &str,
1713    field_id: &str,
1714    selected: Option<&str>,
1715) -> Option<String> {
1716    form_options_html(app_root, fixture_path, form_id, field_id, selected)
1717}
1718
1719/// Performs object value at path in value.
1720fn object_value_at_path_in_value<'a>(root: &'a Value, path: &str) -> Option<&'a Value> {
1721    if path.is_empty() {
1722        return None;
1723    }
1724    let mut current = root;
1725    for segment in path.split('.') {
1726        if segment.is_empty() {
1727            return None;
1728        }
1729        current = current.as_object()?.get(segment)?;
1730    }
1731    Some(current)
1732}
1733
1734/// Performs object field string.
1735///
1736/// # Parameters
1737///
1738/// - `text`: Input consumed by [`crate::runtime::json_commands::object_field_string`].
1739/// - `field`: Input consumed by [`crate::runtime::json_commands::object_field_string`].
1740///
1741/// # Returns
1742///
1743/// Returns [`Some`] when [`crate::runtime::json_commands::object_field_string`] can produce a value and [`None`] otherwise.
1744///
1745/// # Performance
1746///
1747/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_field_string`].
1748///
1749/// # Examples
1750///
1751/// ```rust,ignore
1752/// let _result = pharos_native::runtime::json_commands::object_field_string("{}", "field");
1753/// ```
1754///
1755/// # Related
1756///
1757/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1758pub fn object_field_string(text: &str, field: &str) -> Option<String> {
1759    if field.is_empty() {
1760        return None;
1761    }
1762    serde_json::from_str::<Value>(text)
1763        .ok()?
1764        .as_object()?
1765        .get(field)?
1766        .as_str()
1767        .map(ToOwned::to_owned)
1768}
1769
1770/// Performs object field number.
1771///
1772/// # Parameters
1773///
1774/// - `text`: Input consumed by [`crate::runtime::json_commands::object_field_number`].
1775/// - `field`: Input consumed by [`crate::runtime::json_commands::object_field_number`].
1776///
1777/// # Returns
1778///
1779/// Returns [`Some`] when [`crate::runtime::json_commands::object_field_number`] can produce a value and [`None`] otherwise.
1780///
1781/// # Performance
1782///
1783/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_field_number`].
1784///
1785/// # Examples
1786///
1787/// ```rust,ignore
1788/// let _result = pharos_native::runtime::json_commands::object_field_number("{}", "field");
1789/// ```
1790///
1791/// # Related
1792///
1793/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1794pub fn object_field_number(text: &str, field: &str) -> Option<i64> {
1795    if field.is_empty() {
1796        return None;
1797    }
1798    Some(
1799        serde_json::from_str::<Value>(text)
1800            .ok()?
1801            .as_object()?
1802            .get(field)
1803            .and_then(Value::as_i64)
1804            .unwrap_or(0),
1805    )
1806}
1807
1808/// Performs object field text.
1809///
1810/// # Parameters
1811///
1812/// - `text`: Input consumed by [`crate::runtime::json_commands::object_field_text`].
1813/// - `field`: Input consumed by [`crate::runtime::json_commands::object_field_text`].
1814///
1815/// # Returns
1816///
1817/// Returns [`Some`] when [`crate::runtime::json_commands::object_field_text`] can produce a value and [`None`] otherwise.
1818///
1819/// # Performance
1820///
1821/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_field_text`].
1822///
1823/// # Examples
1824///
1825/// ```rust,ignore
1826/// let _result = pharos_native::runtime::json_commands::object_field_text("{}", "field");
1827/// ```
1828///
1829/// # Related
1830///
1831/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1832pub fn object_field_text(text: &str, field: &str) -> Option<String> {
1833    if field.is_empty() {
1834        return None;
1835    }
1836    let value = serde_json::from_str::<Value>(text)
1837        .ok()?
1838        .as_object()?
1839        .get(field)?
1840        .clone();
1841    (!value.is_null()).then(|| match value {
1842        Value::String(text) => text,
1843        other => serde_json::to_string(&other).unwrap_or_default(),
1844    })
1845}
1846
1847/// Performs object array length.
1848///
1849/// # Parameters
1850///
1851/// - `text`: Input consumed by [`crate::runtime::json_commands::object_array_length`].
1852///
1853/// # Returns
1854///
1855/// Returns [`Some`] when [`crate::runtime::json_commands::object_array_length`] can produce a value and [`None`] otherwise.
1856///
1857/// # Performance
1858///
1859/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_array_length`].
1860///
1861/// # Examples
1862///
1863/// ```rust,ignore
1864/// let _result = pharos_native::runtime::json_commands::object_array_length("{}");
1865/// ```
1866///
1867/// # Related
1868///
1869/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1870pub fn object_array_length(text: &str) -> Option<usize> {
1871    Some(
1872        serde_json::from_str::<Value>(text)
1873            .ok()?
1874            .as_array()
1875            .map(Vec::len)
1876            .unwrap_or(0),
1877    )
1878}
1879
1880/// Performs object array all integers.
1881///
1882/// # Parameters
1883///
1884/// - `text`: Input consumed by [`crate::runtime::json_commands::object_array_all_integers`].
1885///
1886/// # Returns
1887///
1888/// Returns [`Some`] when [`crate::runtime::json_commands::object_array_all_integers`] can produce a value and [`None`] otherwise.
1889///
1890/// # Performance
1891///
1892/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_array_all_integers`].
1893///
1894/// # Examples
1895///
1896/// ```rust,ignore
1897/// let _result = pharos_native::runtime::json_commands::object_array_all_integers("{}");
1898/// ```
1899///
1900/// # Related
1901///
1902/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1903pub fn object_array_all_integers(text: &str) -> Option<bool> {
1904    let root = serde_json::from_str::<Value>(text).ok()?;
1905    let Some(items) = root.as_array() else {
1906        return Some(false);
1907    };
1908    Some(
1909        items
1910            .iter()
1911            .all(|item| item.as_i64().is_some() || item.as_u64().is_some()),
1912    )
1913}
1914
1915/// Performs object path JSON.
1916///
1917/// # Parameters
1918///
1919/// - `text`: Input consumed by [`crate::runtime::json_commands::object_path_json`].
1920/// - `path`: Input consumed by [`crate::runtime::json_commands::object_path_json`].
1921///
1922/// # Returns
1923///
1924/// Returns [`Some`] when [`crate::runtime::json_commands::object_path_json`] can produce a value and [`None`] otherwise.
1925///
1926/// # Performance
1927///
1928/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_path_json`].
1929///
1930/// # Examples
1931///
1932/// ```rust,ignore
1933/// let _result = pharos_native::runtime::json_commands::object_path_json("{}", std::path::Path::new("fixture.json"));
1934/// ```
1935///
1936/// # Related
1937///
1938/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1939pub fn object_path_json(text: &str, path: &str) -> Option<String> {
1940    let root = serde_json::from_str::<Value>(text).ok()?;
1941    let Some(value) = object_value_at_path_in_value(&root, path) else {
1942        return Some("null".to_owned());
1943    };
1944    serde_json::to_string(value).ok()
1945}
1946
1947/// Performs object path string.
1948///
1949/// # Parameters
1950///
1951/// - `text`: Input consumed by [`crate::runtime::json_commands::object_path_string`].
1952/// - `path`: Input consumed by [`crate::runtime::json_commands::object_path_string`].
1953///
1954/// # Returns
1955///
1956/// Returns [`Some`] when [`crate::runtime::json_commands::object_path_string`] can produce a value and [`None`] otherwise.
1957///
1958/// # Performance
1959///
1960/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_path_string`].
1961///
1962/// # Examples
1963///
1964/// ```rust,ignore
1965/// let _result = pharos_native::runtime::json_commands::object_path_string("{}", std::path::Path::new("fixture.json"));
1966/// ```
1967///
1968/// # Related
1969///
1970/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
1971pub fn object_path_string(text: &str, path: &str) -> Option<String> {
1972    let root = serde_json::from_str::<Value>(text).ok()?;
1973    object_value_at_path_in_value(&root, path)?
1974        .as_str()
1975        .map(ToOwned::to_owned)
1976}
1977
1978/// Performs object path number.
1979///
1980/// # Parameters
1981///
1982/// - `text`: Input consumed by [`crate::runtime::json_commands::object_path_number`].
1983/// - `path`: Input consumed by [`crate::runtime::json_commands::object_path_number`].
1984///
1985/// # Returns
1986///
1987/// Returns [`Some`] when [`crate::runtime::json_commands::object_path_number`] can produce a value and [`None`] otherwise.
1988///
1989/// # Performance
1990///
1991/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_path_number`].
1992///
1993/// # Examples
1994///
1995/// ```rust,ignore
1996/// let _result = pharos_native::runtime::json_commands::object_path_number("{}", std::path::Path::new("fixture.json"));
1997/// ```
1998///
1999/// # Related
2000///
2001/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2002pub fn object_path_number(text: &str, path: &str) -> Option<i64> {
2003    let root = serde_json::from_str::<Value>(text).ok()?;
2004    Some(
2005        object_value_at_path_in_value(&root, path)
2006            .and_then(Value::as_i64)
2007            .unwrap_or(0),
2008    )
2009}
2010
2011/// Performs object path bool.
2012///
2013/// # Parameters
2014///
2015/// - `text`: Input consumed by [`crate::runtime::json_commands::object_path_bool`].
2016/// - `path`: Input consumed by [`crate::runtime::json_commands::object_path_bool`].
2017///
2018/// # Returns
2019///
2020/// Returns [`Some`] when [`crate::runtime::json_commands::object_path_bool`] can produce a value and [`None`] otherwise.
2021///
2022/// # Performance
2023///
2024/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_path_bool`].
2025///
2026/// # Examples
2027///
2028/// ```rust,ignore
2029/// let _result = pharos_native::runtime::json_commands::object_path_bool("{}", std::path::Path::new("fixture.json"));
2030/// ```
2031///
2032/// # Related
2033///
2034/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2035pub fn object_path_bool(text: &str, path: &str) -> Option<bool> {
2036    let root = serde_json::from_str::<Value>(text).ok()?;
2037    Some(
2038        object_value_at_path_in_value(&root, path)
2039            .and_then(Value::as_bool)
2040            .unwrap_or(false),
2041    )
2042}
2043
2044/// Handles object field string command.
2045///
2046/// # Parameters
2047///
2048/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_field_string_command`].
2049/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_object_field_string_command`].
2050///
2051/// # Returns
2052///
2053/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_field_string_command`] can produce a value and [`None`] otherwise.
2054///
2055/// # Examples
2056///
2057/// ```rust,ignore
2058/// let _result = pharos_native::runtime::json_commands::handle_object_field_string_command("{}", "field");
2059/// ```
2060///
2061/// # Related
2062///
2063/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2064pub fn handle_object_field_string_command(text: &str, field: &str) -> Option<String> {
2065    object_field_string(text, field)
2066}
2067
2068/// Handles object field number command.
2069///
2070/// # Parameters
2071///
2072/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_field_number_command`].
2073/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_object_field_number_command`].
2074///
2075/// # Returns
2076///
2077/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_field_number_command`] can produce a value and [`None`] otherwise.
2078///
2079/// # Examples
2080///
2081/// ```rust,ignore
2082/// let _result = pharos_native::runtime::json_commands::handle_object_field_number_command("{}", "field");
2083/// ```
2084///
2085/// # Related
2086///
2087/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2088pub fn handle_object_field_number_command(text: &str, field: &str) -> Option<i64> {
2089    object_field_number(text, field)
2090}
2091
2092/// Handles object field text command.
2093///
2094/// # Parameters
2095///
2096/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_field_text_command`].
2097/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_object_field_text_command`].
2098///
2099/// # Returns
2100///
2101/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_field_text_command`] can produce a value and [`None`] otherwise.
2102///
2103/// # Examples
2104///
2105/// ```rust,ignore
2106/// let _result = pharos_native::runtime::json_commands::handle_object_field_text_command("{}", "field");
2107/// ```
2108///
2109/// # Related
2110///
2111/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2112pub fn handle_object_field_text_command(text: &str, field: &str) -> Option<String> {
2113    object_field_text(text, field)
2114}
2115
2116/// Handles object array length command.
2117///
2118/// # Parameters
2119///
2120/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_array_length_command`].
2121///
2122/// # Returns
2123///
2124/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_array_length_command`] can produce a value and [`None`] otherwise.
2125///
2126/// # Examples
2127///
2128/// ```rust,ignore
2129/// let _result = pharos_native::runtime::json_commands::handle_object_array_length_command("{}");
2130/// ```
2131///
2132/// # Related
2133///
2134/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2135pub fn handle_object_array_length_command(text: &str) -> Option<usize> {
2136    object_array_length(text)
2137}
2138
2139/// Handles object array all integers command.
2140///
2141/// # Parameters
2142///
2143/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_array_all_integers_command`].
2144///
2145/// # Returns
2146///
2147/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_array_all_integers_command`] can produce a value and [`None`] otherwise.
2148///
2149/// # Examples
2150///
2151/// ```rust,ignore
2152/// let _result = pharos_native::runtime::json_commands::handle_object_array_all_integers_command("{}");
2153/// ```
2154///
2155/// # Related
2156///
2157/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2158pub fn handle_object_array_all_integers_command(text: &str) -> Option<bool> {
2159    object_array_all_integers(text)
2160}
2161
2162/// Handles object path JSON command.
2163///
2164/// # Parameters
2165///
2166/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_path_json_command`].
2167/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_object_path_json_command`].
2168///
2169/// # Returns
2170///
2171/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_path_json_command`] can produce a value and [`None`] otherwise.
2172///
2173/// # Examples
2174///
2175/// ```rust,ignore
2176/// let _result = pharos_native::runtime::json_commands::handle_object_path_json_command("{}", std::path::Path::new("fixture.json"));
2177/// ```
2178///
2179/// # Related
2180///
2181/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2182pub fn handle_object_path_json_command(text: &str, path: &str) -> Option<String> {
2183    object_path_json(text, path)
2184}
2185
2186/// Handles object path string command.
2187///
2188/// # Parameters
2189///
2190/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_path_string_command`].
2191/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_object_path_string_command`].
2192///
2193/// # Returns
2194///
2195/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_path_string_command`] can produce a value and [`None`] otherwise.
2196///
2197/// # Examples
2198///
2199/// ```rust,ignore
2200/// let _result = pharos_native::runtime::json_commands::handle_object_path_string_command("{}", std::path::Path::new("fixture.json"));
2201/// ```
2202///
2203/// # Related
2204///
2205/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2206pub fn handle_object_path_string_command(text: &str, path: &str) -> Option<String> {
2207    object_path_string(text, path)
2208}
2209
2210/// Handles object path number command.
2211///
2212/// # Parameters
2213///
2214/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_path_number_command`].
2215/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_object_path_number_command`].
2216///
2217/// # Returns
2218///
2219/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_path_number_command`] can produce a value and [`None`] otherwise.
2220///
2221/// # Examples
2222///
2223/// ```rust,ignore
2224/// let _result = pharos_native::runtime::json_commands::handle_object_path_number_command("{}", std::path::Path::new("fixture.json"));
2225/// ```
2226///
2227/// # Related
2228///
2229/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2230pub fn handle_object_path_number_command(text: &str, path: &str) -> Option<i64> {
2231    object_path_number(text, path)
2232}
2233
2234/// Handles object path bool command.
2235///
2236/// # Parameters
2237///
2238/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_path_bool_command`].
2239/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_object_path_bool_command`].
2240///
2241/// # Returns
2242///
2243/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_path_bool_command`] can produce a value and [`None`] otherwise.
2244///
2245/// # Examples
2246///
2247/// ```rust,ignore
2248/// let _result = pharos_native::runtime::json_commands::handle_object_path_bool_command("{}", std::path::Path::new("fixture.json"));
2249/// ```
2250///
2251/// # Related
2252///
2253/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2254pub fn handle_object_path_bool_command(text: &str, path: &str) -> Option<bool> {
2255    object_path_bool(text, path)
2256}
2257
2258/// Performs object path array length.
2259///
2260/// # Parameters
2261///
2262/// - `text`: Input consumed by [`crate::runtime::json_commands::object_path_array_length`].
2263/// - `path`: Input consumed by [`crate::runtime::json_commands::object_path_array_length`].
2264///
2265/// # Returns
2266///
2267/// Returns [`Some`] when [`crate::runtime::json_commands::object_path_array_length`] can produce a value and [`None`] otherwise.
2268///
2269/// # Performance
2270///
2271/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_path_array_length`].
2272///
2273/// # Examples
2274///
2275/// ```rust,ignore
2276/// let _result = pharos_native::runtime::json_commands::object_path_array_length("{}", std::path::Path::new("fixture.json"));
2277/// ```
2278///
2279/// # Related
2280///
2281/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2282pub fn object_path_array_length(text: &str, path: &str) -> Option<usize> {
2283    let root = serde_json::from_str::<Value>(text).ok()?;
2284    Some(
2285        object_value_at_path_in_value(&root, path)
2286            .and_then(Value::as_array)
2287            .map(Vec::len)
2288            .unwrap_or(0),
2289    )
2290}
2291
2292/// Performs object array item JSON lines.
2293///
2294/// # Parameters
2295///
2296/// - `text`: Input consumed by [`crate::runtime::json_commands::object_array_item_json_lines`].
2297///
2298/// # Returns
2299///
2300/// Returns [`Some`] when [`crate::runtime::json_commands::object_array_item_json_lines`] can produce a value and [`None`] otherwise.
2301///
2302/// # Performance
2303///
2304/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_array_item_json_lines`].
2305///
2306/// # Examples
2307///
2308/// ```rust,ignore
2309/// let _result = pharos_native::runtime::json_commands::object_array_item_json_lines("{}");
2310/// ```
2311///
2312/// # Related
2313///
2314/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2315pub fn object_array_item_json_lines(text: &str) -> Option<Vec<String>> {
2316    let root = serde_json::from_str::<Value>(text).ok()?;
2317    let mut lines = Vec::new();
2318    for item in root.as_array()? {
2319        lines.push(serde_json::to_string(item).ok()?);
2320    }
2321    Some(lines)
2322}
2323
2324/// Performs object array lines.
2325///
2326/// # Parameters
2327///
2328/// - `text`: Input consumed by [`crate::runtime::json_commands::object_array_lines`].
2329///
2330/// # Returns
2331///
2332/// Returns [`Some`] when [`crate::runtime::json_commands::object_array_lines`] can produce a value and [`None`] otherwise.
2333///
2334/// # Performance
2335///
2336/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_array_lines`].
2337///
2338/// # Examples
2339///
2340/// ```rust,ignore
2341/// let _result = pharos_native::runtime::json_commands::object_array_lines("{}");
2342/// ```
2343///
2344/// # Related
2345///
2346/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2347pub fn object_array_lines(text: &str) -> Option<Vec<String>> {
2348    let root = serde_json::from_str::<Value>(text).ok()?;
2349    let mut lines = Vec::new();
2350    for item in root.as_array()? {
2351        match item {
2352            Value::String(text) => lines.push(text.clone()),
2353            other => lines.push(serde_json::to_string(other).ok()?),
2354        }
2355    }
2356    Some(lines)
2357}
2358
2359/// Performs object relative path array to absolute JSON.
2360///
2361/// # Parameters
2362///
2363/// - `text`: Input consumed by [`crate::runtime::json_commands::object_relative_path_array_to_absolute_json`].
2364/// - `app_root`: Input consumed by [`crate::runtime::json_commands::object_relative_path_array_to_absolute_json`].
2365///
2366/// # Returns
2367///
2368/// Returns [`Some`] when [`crate::runtime::json_commands::object_relative_path_array_to_absolute_json`] can produce a value and [`None`] otherwise.
2369///
2370/// # Performance
2371///
2372/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_relative_path_array_to_absolute_json`].
2373///
2374/// # Examples
2375///
2376/// ```rust,ignore
2377/// let _result = pharos_native::runtime::json_commands::object_relative_path_array_to_absolute_json("{}", std::path::Path::new("apps/dev_docs"));
2378/// ```
2379///
2380/// # Related
2381///
2382/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2383pub fn object_relative_path_array_to_absolute_json(text: &str, app_root: &Path) -> Option<String> {
2384    if app_root.as_os_str().is_empty() {
2385        return None;
2386    }
2387    let root = serde_json::from_str::<Value>(text).ok()?;
2388    let Some(items) = root.as_array() else {
2389        return Some("[]".to_owned());
2390    };
2391    let absolute: Vec<Value> = items
2392        .iter()
2393        .filter_map(|item| item.as_str())
2394        .map(|value| {
2395            if value.starts_with('/') {
2396                Value::String(value.to_owned())
2397            } else {
2398                Value::String(app_root.join(value).to_string_lossy().into_owned())
2399            }
2400        })
2401        .collect();
2402    serde_json::to_string(&absolute).ok()
2403}
2404
2405/// Handles object path array length command.
2406///
2407/// # Parameters
2408///
2409/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_path_array_length_command`].
2410/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_object_path_array_length_command`].
2411///
2412/// # Returns
2413///
2414/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_path_array_length_command`] can produce a value and [`None`] otherwise.
2415///
2416/// # Examples
2417///
2418/// ```rust,ignore
2419/// let _result = pharos_native::runtime::json_commands::handle_object_path_array_length_command("{}", std::path::Path::new("fixture.json"));
2420/// ```
2421///
2422/// # Related
2423///
2424/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2425pub fn handle_object_path_array_length_command(text: &str, path: &str) -> Option<usize> {
2426    object_path_array_length(text, path)
2427}
2428
2429/// Handles object array item JSON lines command.
2430///
2431/// # Parameters
2432///
2433/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_array_item_json_lines_command`].
2434///
2435/// # Returns
2436///
2437/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_array_item_json_lines_command`] can produce a value and [`None`] otherwise.
2438///
2439/// # Examples
2440///
2441/// ```rust,ignore
2442/// let _result = pharos_native::runtime::json_commands::handle_object_array_item_json_lines_command("{}");
2443/// ```
2444///
2445/// # Related
2446///
2447/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2448pub fn handle_object_array_item_json_lines_command(text: &str) -> Option<String> {
2449    object_array_item_json_lines(text).map(|lines| lines.join("\n"))
2450}
2451
2452/// Handles object array lines command.
2453///
2454/// # Parameters
2455///
2456/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_array_lines_command`].
2457///
2458/// # Returns
2459///
2460/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_array_lines_command`] can produce a value and [`None`] otherwise.
2461///
2462/// # Examples
2463///
2464/// ```rust,ignore
2465/// let _result = pharos_native::runtime::json_commands::handle_object_array_lines_command("{}");
2466/// ```
2467///
2468/// # Related
2469///
2470/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2471pub fn handle_object_array_lines_command(text: &str) -> Option<String> {
2472    object_array_lines(text).map(|lines| lines.join("\n"))
2473}
2474
2475/// Handles object relative path array to absolute JSON command.
2476///
2477/// # Parameters
2478///
2479/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_object_relative_path_array_to_absolute_json_command`].
2480/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_object_relative_path_array_to_absolute_json_command`].
2481///
2482/// # Returns
2483///
2484/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_relative_path_array_to_absolute_json_command`] can produce a value and [`None`] otherwise.
2485///
2486/// # Examples
2487///
2488/// ```rust,ignore
2489/// let _result = pharos_native::runtime::json_commands::handle_object_relative_path_array_to_absolute_json_command("{}", std::path::Path::new("apps/dev_docs"));
2490/// ```
2491///
2492/// # Related
2493///
2494/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2495pub fn handle_object_relative_path_array_to_absolute_json_command(
2496    text: &str,
2497    app_root: &Path,
2498) -> Option<String> {
2499    object_relative_path_array_to_absolute_json(text, app_root)
2500}
2501
2502/// Performs file compact object.
2503///
2504/// # Parameters
2505///
2506/// - `path`: Input consumed by [`crate::runtime::json_commands::file_compact_object`].
2507///
2508/// # Returns
2509///
2510/// Returns [`Some`] when [`crate::runtime::json_commands::file_compact_object`] can produce a value and [`None`] otherwise.
2511///
2512/// # Examples
2513///
2514/// ```rust,ignore
2515/// let _result = pharos_native::runtime::json_commands::file_compact_object(std::path::Path::new("fixture.json"));
2516/// ```
2517///
2518/// # Related
2519///
2520/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2521pub fn file_compact_object(path: &Path) -> Option<String> {
2522    let root = read_json_file(path)?;
2523    if !root.is_object() {
2524        return Some("{}".to_owned());
2525    }
2526    serde_json::to_string(&root).ok()
2527}
2528
2529/// Performs file field string.
2530///
2531/// # Parameters
2532///
2533/// - `path`: Input consumed by [`crate::runtime::json_commands::file_field_string`].
2534/// - `field`: Input consumed by [`crate::runtime::json_commands::file_field_string`].
2535///
2536/// # Returns
2537///
2538/// Returns [`Some`] when [`crate::runtime::json_commands::file_field_string`] can produce a value and [`None`] otherwise.
2539///
2540/// # Examples
2541///
2542/// ```rust,ignore
2543/// let _result = pharos_native::runtime::json_commands::file_field_string(std::path::Path::new("fixture.json"), "field");
2544/// ```
2545///
2546/// # Related
2547///
2548/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2549pub fn file_field_string(path: &Path, field: &str) -> Option<String> {
2550    if field.is_empty() {
2551        return None;
2552    }
2553    read_json_file(path)?
2554        .as_object()?
2555        .get(field)?
2556        .as_str()
2557        .map(ToOwned::to_owned)
2558}
2559
2560/// Performs file field number.
2561///
2562/// # Parameters
2563///
2564/// - `path`: Input consumed by [`crate::runtime::json_commands::file_field_number`].
2565/// - `field`: Input consumed by [`crate::runtime::json_commands::file_field_number`].
2566///
2567/// # Returns
2568///
2569/// Returns [`Some`] when [`crate::runtime::json_commands::file_field_number`] can produce a value and [`None`] otherwise.
2570///
2571/// # Examples
2572///
2573/// ```rust,ignore
2574/// let _result = pharos_native::runtime::json_commands::file_field_number(std::path::Path::new("fixture.json"), "field");
2575/// ```
2576///
2577/// # Related
2578///
2579/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2580pub fn file_field_number(path: &Path, field: &str) -> Option<i64> {
2581    if field.is_empty() {
2582        return None;
2583    }
2584    Some(
2585        read_json_file(path)?
2586            .as_object()?
2587            .get(field)
2588            .and_then(Value::as_i64)
2589            .unwrap_or(0),
2590    )
2591}
2592
2593/// Performs file section length.
2594///
2595/// # Parameters
2596///
2597/// - `path`: Input consumed by [`crate::runtime::json_commands::file_section_length`].
2598/// - `section`: Input consumed by [`crate::runtime::json_commands::file_section_length`].
2599///
2600/// # Returns
2601///
2602/// Returns [`Some`] when [`crate::runtime::json_commands::file_section_length`] can produce a value and [`None`] otherwise.
2603///
2604/// # Examples
2605///
2606/// ```rust,ignore
2607/// let _result = pharos_native::runtime::json_commands::file_section_length(std::path::Path::new("fixture.json"), "items");
2608/// ```
2609///
2610/// # Related
2611///
2612/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2613pub fn file_section_length(path: &Path, section: &str) -> Option<usize> {
2614    if section.is_empty() {
2615        return None;
2616    }
2617    Some(
2618        read_json_file(path)?
2619            .as_object()?
2620            .get(section)
2621            .and_then(Value::as_array)
2622            .map(Vec::len)
2623            .unwrap_or(0),
2624    )
2625}
2626
2627/// Handles file compact object command.
2628///
2629/// # Parameters
2630///
2631/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_file_compact_object_command`].
2632///
2633/// # Returns
2634///
2635/// Returns [`Some`] when [`crate::runtime::json_commands::handle_file_compact_object_command`] can produce a value and [`None`] otherwise.
2636///
2637/// # Examples
2638///
2639/// ```rust,ignore
2640/// let _result = pharos_native::runtime::json_commands::handle_file_compact_object_command(std::path::Path::new("fixture.json"));
2641/// ```
2642///
2643/// # Related
2644///
2645/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2646pub fn handle_file_compact_object_command(path: &Path) -> Option<String> {
2647    file_compact_object(path)
2648}
2649
2650/// Handles file field string command.
2651///
2652/// # Parameters
2653///
2654/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_file_field_string_command`].
2655/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_file_field_string_command`].
2656///
2657/// # Returns
2658///
2659/// Returns [`Some`] when [`crate::runtime::json_commands::handle_file_field_string_command`] can produce a value and [`None`] otherwise.
2660///
2661/// # Examples
2662///
2663/// ```rust,ignore
2664/// let _result = pharos_native::runtime::json_commands::handle_file_field_string_command(std::path::Path::new("fixture.json"), "field");
2665/// ```
2666///
2667/// # Related
2668///
2669/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2670pub fn handle_file_field_string_command(path: &Path, field: &str) -> Option<String> {
2671    file_field_string(path, field)
2672}
2673
2674/// Handles file field number command.
2675///
2676/// # Parameters
2677///
2678/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_file_field_number_command`].
2679/// - `field`: Input consumed by [`crate::runtime::json_commands::handle_file_field_number_command`].
2680///
2681/// # Returns
2682///
2683/// Returns [`Some`] when [`crate::runtime::json_commands::handle_file_field_number_command`] can produce a value and [`None`] otherwise.
2684///
2685/// # Examples
2686///
2687/// ```rust,ignore
2688/// let _result = pharos_native::runtime::json_commands::handle_file_field_number_command(std::path::Path::new("fixture.json"), "field");
2689/// ```
2690///
2691/// # Related
2692///
2693/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2694pub fn handle_file_field_number_command(path: &Path, field: &str) -> Option<i64> {
2695    file_field_number(path, field)
2696}
2697
2698/// Handles file section length command.
2699///
2700/// # Parameters
2701///
2702/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_file_section_length_command`].
2703/// - `section`: Input consumed by [`crate::runtime::json_commands::handle_file_section_length_command`].
2704///
2705/// # Returns
2706///
2707/// Returns [`Some`] when [`crate::runtime::json_commands::handle_file_section_length_command`] can produce a value and [`None`] otherwise.
2708///
2709/// # Examples
2710///
2711/// ```rust,ignore
2712/// let _result = pharos_native::runtime::json_commands::handle_file_section_length_command(std::path::Path::new("fixture.json"), "items");
2713/// ```
2714///
2715/// # Related
2716///
2717/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2718pub fn handle_file_section_length_command(path: &Path, section: &str) -> Option<usize> {
2719    file_section_length(path, section)
2720}
2721
2722/// Performs manifest database contract path.
2723///
2724/// # Parameters
2725///
2726/// - `app_root`: Application root whose manifest-owned database contract path is being resolved.
2727///
2728/// # Returns
2729///
2730/// Returns [`Some`] when [`crate::runtime::json_commands::manifest_database_contract_path`] can produce a value and [`None`] otherwise.
2731///
2732/// # Performance
2733///
2734/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::manifest_database_contract_path`].
2735///
2736/// # Examples
2737///
2738/// ```rust,ignore
2739/// let _result = pharos_native::runtime::json_commands::manifest_database_contract_path(todo!());
2740/// ```
2741///
2742/// # Related
2743///
2744/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2745pub(crate) fn manifest_database_contract_path(app_root: &Path) -> Option<String> {
2746    let manifest_path = if app_root.join("pharos.app.json").exists() {
2747        app_root.join("pharos.app.json")
2748    } else {
2749        app_root.join("pharos.app.yml")
2750    };
2751    let manifest = read_json_or_yaml_file(&manifest_path)?;
2752    manifest
2753        .get("database")?
2754        .get("migration_contract")?
2755        .as_str()
2756        .filter(|path| !path.trim().is_empty())
2757        .map(ToOwned::to_owned)
2758}
2759
2760/// Declared database ownership never falls back to file state after a resolution failure.
2761pub(crate) fn manifest_declares_database(app_root: &Path) -> bool {
2762    let manifest_path = if app_root.join("pharos.app.yml").exists() {
2763        app_root.join("pharos.app.yml")
2764    } else {
2765        app_root.join("pharos.app.json")
2766    };
2767    manifest_path.exists()
2768        && read_json_or_yaml_file(&manifest_path)
2769            .is_none_or(|manifest| manifest.get("database").is_some())
2770}
2771
2772/// Performs relational runtime authority enabled.
2773fn relational_runtime_authority_enabled(app_root: &Path) -> bool {
2774    super::database::relational_runtime_authority_enabled(app_root)
2775}
2776
2777/// Performs dynamic config value.
2778///
2779/// # Parameters
2780///
2781/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_config_value`].
2782/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::dynamic_config_value`].
2783/// - `key`: Input consumed by [`crate::runtime::json_commands::dynamic_config_value`].
2784///
2785/// # Returns
2786///
2787/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_config_value`] can produce a value and [`None`] otherwise.
2788///
2789/// # Examples
2790///
2791/// ```rust,ignore
2792/// let _result = pharos_native::runtime::json_commands::dynamic_config_value(std::path::Path::new("apps/dev_docs"), todo!(), "key");
2793/// ```
2794///
2795/// # Related
2796///
2797/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2798pub fn dynamic_config_value(
2799    app_root: &Path,
2800    runtime_conf_path: Option<&Path>,
2801    key: &str,
2802) -> Option<String> {
2803    super::cache::dynamic_config_allowlist_value(app_root, runtime_conf_path, key)
2804}
2805
2806/// Performs dynamic safe upload filename.
2807///
2808/// # Parameters
2809///
2810/// - `raw_name`: Input consumed by [`crate::runtime::json_commands::dynamic_safe_upload_filename`].
2811///
2812/// # Returns
2813///
2814/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_safe_upload_filename`] can produce a value and [`None`] otherwise.
2815///
2816/// # Performance
2817///
2818/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_safe_upload_filename`].
2819///
2820/// # Examples
2821///
2822/// ```rust,ignore
2823/// let _result = pharos_native::runtime::json_commands::dynamic_safe_upload_filename(Some("file.txt"));
2824/// ```
2825///
2826/// # Related
2827///
2828/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2829pub fn dynamic_safe_upload_filename(raw_name: Option<&str>) -> Option<String> {
2830    let mut base_name = raw_name.unwrap_or("");
2831    if let Some(index) = base_name.rfind(['/', '\\']) {
2832        base_name = &base_name[index + 1..];
2833    }
2834    let mut safe_name = String::with_capacity(base_name.len());
2835    for ch in base_name.chars() {
2836        if ch.is_ascii_alphanumeric() || matches!(ch, '.' | '_' | '-') {
2837            safe_name.push(ch);
2838        } else {
2839            safe_name.push('_');
2840        }
2841    }
2842    let safe_name = safe_name
2843        .trim_start_matches(['_', '.', '-'])
2844        .trim_end_matches(['_', '.', '-'])
2845        .to_owned();
2846    Some(safe_name)
2847}
2848
2849/// Performs dynamic media disk path.
2850///
2851/// # Parameters
2852///
2853/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_media_disk_path`].
2854/// - `media_url`: Input consumed by [`crate::runtime::json_commands::dynamic_media_disk_path`].
2855///
2856/// # Returns
2857///
2858/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_media_disk_path`] can produce a value and [`None`] otherwise.
2859///
2860/// # Examples
2861///
2862/// ```rust,ignore
2863/// let _result = pharos_native::runtime::json_commands::dynamic_media_disk_path(std::path::Path::new("build/dev_docs"), todo!());
2864/// ```
2865///
2866/// # Related
2867///
2868/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2869pub fn dynamic_media_disk_path(artifact_dir: &Path, media_url: &str) -> Option<String> {
2870    if artifact_dir.as_os_str().is_empty()
2871        || !media_url.starts_with("/media/")
2872        || media_url[7..]
2873            .split('/')
2874            .any(|part| part.is_empty() || part == ".." || part.contains(['\\', '\0']))
2875    {
2876        return None;
2877    }
2878    Some(
2879        super::config::app_media_root(artifact_dir)?
2880            .join(&media_url[7..])
2881            .to_string_lossy()
2882            .into_owned(),
2883    )
2884}
2885
2886/// Performs dynamic ensure business media tree.
2887///
2888/// # Parameters
2889///
2890/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_ensure_business_media_tree`].
2891/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_ensure_business_media_tree`].
2892///
2893/// # Returns
2894///
2895/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_ensure_business_media_tree`].
2896///
2897/// # Performance
2898///
2899/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_ensure_business_media_tree`].
2900///
2901/// # Examples
2902///
2903/// ```rust,ignore
2904/// let _result = pharos_native::runtime::json_commands::dynamic_ensure_business_media_tree(std::path::Path::new("build/dev_docs"), "demo");
2905/// ```
2906///
2907/// # Related
2908///
2909/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2910pub fn dynamic_ensure_business_media_tree(artifact_dir: &Path, business_slug: &str) -> i32 {
2911    if artifact_dir.as_os_str().is_empty() || business_slug.is_empty() {
2912        return 64;
2913    }
2914    let Some(policy_root) = super::declarative::declarative_source_load_fixture(
2915        artifact_dir,
2916        "data/contracts/media-policy",
2917    ) else {
2918        return 69;
2919    };
2920    let Some(entries) = policy_root.get("media_subtrees").and_then(Value::as_array) else {
2921        return 69;
2922    };
2923    let Some(entry) = entries.iter().find(|entry| {
2924        entry
2925            .get("entity_type")
2926            .and_then(Value::as_str)
2927            .is_some_and(|value| value == "business")
2928    }) else {
2929        return 0;
2930    };
2931    let Some(base_template) = entry.get("base_path_template").and_then(Value::as_str) else {
2932        return 64;
2933    };
2934    let base_path = base_template.replace("{slug}", business_slug);
2935    let Some(media_root) = super::config::app_media_root(artifact_dir) else {
2936        return 64;
2937    };
2938    let Some(relative) = base_path.strip_prefix("media/") else {
2939        return 64;
2940    };
2941    let base_path = media_root.join(relative);
2942    if fs::create_dir_all(&base_path).is_err() {
2943        return 69;
2944    }
2945    if let Some(subdirs) = entry.get("subdirectories").and_then(Value::as_array) {
2946        for subdir in subdirs.iter().filter_map(Value::as_str) {
2947            if fs::create_dir_all(base_path.join(subdir)).is_err() {
2948                return 69;
2949            }
2950        }
2951    }
2952    0
2953}
2954
2955/// Performs dynamic remove business media URL file.
2956///
2957/// # Parameters
2958///
2959/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_remove_business_media_url_file`].
2960/// - `media_url`: Input consumed by [`crate::runtime::json_commands::dynamic_remove_business_media_url_file`].
2961///
2962/// # Returns
2963///
2964/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_remove_business_media_url_file`].
2965///
2966/// # Examples
2967///
2968/// ```rust,ignore
2969/// let _result = pharos_native::runtime::json_commands::dynamic_remove_business_media_url_file(std::path::Path::new("build/dev_docs"), todo!());
2970/// ```
2971///
2972/// # Related
2973///
2974/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
2975pub fn dynamic_remove_business_media_url_file(artifact_dir: &Path, media_url: &str) -> i32 {
2976    if artifact_dir.as_os_str().is_empty() || !media_url.starts_with("/media/businesses/") {
2977        return 0;
2978    }
2979    if let Some(disk_path) = dynamic_media_disk_path(artifact_dir, media_url) {
2980        let path = Path::new(&disk_path);
2981        if path.exists() {
2982            let _ = fs::remove_file(path);
2983        }
2984    }
2985    0
2986}
2987
2988/// Performs dynamic store uploaded media.
2989///
2990/// # Parameters
2991///
2992/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2993/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2994/// - `body_path`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2995/// - `field_name`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2996/// - `target_url_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2997/// - `fallback_filename`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media`].
2998///
2999/// # Returns
3000///
3001/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_store_uploaded_media`] can produce a value and [`None`] otherwise.
3002///
3003/// # Examples
3004///
3005/// ```rust,ignore
3006/// let _result = pharos_native::runtime::json_commands::dynamic_store_uploaded_media(std::path::Path::new("build/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
3007/// ```
3008///
3009/// # Related
3010///
3011/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3012pub fn dynamic_store_uploaded_media(
3013    artifact_dir: &Path,
3014    content_type: &str,
3015    body_path: &Path,
3016    field_name: &str,
3017    target_url_dir: &str,
3018    fallback_filename: Option<&str>,
3019) -> Option<String> {
3020    dynamic_store_uploaded_media_bytes(
3021        artifact_dir,
3022        content_type,
3023        &fs::read(body_path).ok()?,
3024        field_name,
3025        target_url_dir,
3026        fallback_filename,
3027    )
3028}
3029
3030/// Stores one uploaded media part from an in-memory multipart body.
3031///
3032/// # Parameters
3033///
3034/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3035/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3036/// - `body`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3037/// - `field_name`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3038/// - `target_url_dir`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3039/// - `fallback_filename`: Input consumed by [`crate::runtime::json_commands::dynamic_store_uploaded_media_from_body`].
3040///
3041/// # Returns
3042///
3043/// Returns [`Some`] when one non-empty media part was stored and [`None`] otherwise.
3044///
3045/// # Examples
3046///
3047/// ```rust,ignore
3048/// let _result = pharos_native::runtime::json_commands::dynamic_store_uploaded_media_from_body(std::path::Path::new("build/dev_docs"), todo!(), b"", todo!(), todo!(), todo!());
3049/// ```
3050///
3051/// # Related
3052///
3053/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3054pub fn dynamic_store_uploaded_media_from_body(
3055    artifact_dir: &Path,
3056    content_type: &str,
3057    body: &[u8],
3058    field_name: &str,
3059    target_url_dir: &str,
3060    fallback_filename: Option<&str>,
3061) -> Option<String> {
3062    dynamic_store_uploaded_media_bytes(
3063        artifact_dir,
3064        content_type,
3065        body,
3066        field_name,
3067        target_url_dir,
3068        fallback_filename,
3069    )
3070}
3071
3072/// Performs dynamic store uploaded media bytes.
3073fn dynamic_store_uploaded_media_bytes(
3074    artifact_dir: &Path,
3075    content_type: &str,
3076    body: &[u8],
3077    field_name: &str,
3078    target_url_dir: &str,
3079    fallback_filename: Option<&str>,
3080) -> Option<String> {
3081    if artifact_dir.as_os_str().is_empty()
3082        || content_type.is_empty()
3083        || field_name.is_empty()
3084        || target_url_dir.is_empty()
3085    {
3086        return None;
3087    }
3088    let part = multipart_find_part_from_body(body, content_type, field_name)?;
3089    if part.content.is_empty() {
3090        return None;
3091    }
3092    let mut safe_filename = dynamic_safe_upload_filename(part.filename.as_deref())?;
3093    if safe_filename.is_empty() {
3094        safe_filename = dynamic_safe_upload_filename(fallback_filename)?.to_owned();
3095    }
3096    if safe_filename.is_empty() {
3097        return None;
3098    }
3099    let target_dir = artifact_dir.join(target_url_dir.trim_start_matches('/'));
3100    fs::create_dir_all(&target_dir).ok()?;
3101    super::fs::write_file_within(
3102        artifact_dir,
3103        &target_dir.join(&safe_filename),
3104        &part.content,
3105        0o640,
3106    )
3107    .ok()?;
3108    Some(format!("{target_url_dir}/{safe_filename}"))
3109}
3110
3111/// Handles dynamic config value command.
3112///
3113/// # Parameters
3114///
3115/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_config_value_command`].
3116/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_config_value_command`].
3117/// - `key`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_config_value_command`].
3118///
3119/// # Returns
3120///
3121/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_config_value_command`] can produce a value and [`None`] otherwise.
3122///
3123/// # Examples
3124///
3125/// ```rust,ignore
3126/// let _result = pharos_native::runtime::json_commands::handle_dynamic_config_value_command(std::path::Path::new("apps/dev_docs"), todo!(), "key");
3127/// ```
3128///
3129/// # Related
3130///
3131/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3132pub fn handle_dynamic_config_value_command(
3133    app_root: &Path,
3134    runtime_conf_path: Option<&Path>,
3135    key: &str,
3136) -> Option<String> {
3137    dynamic_config_value(app_root, runtime_conf_path, key)
3138}
3139
3140/// Handles dynamic relational backend command.
3141///
3142/// # Parameters
3143///
3144/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_backend_command`].
3145/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_backend_command`].
3146///
3147/// # Returns
3148///
3149/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_relational_backend_command`] can produce a value and [`None`] otherwise.
3150///
3151/// # Examples
3152///
3153/// ```rust,ignore
3154/// let _result = pharos_native::runtime::json_commands::handle_dynamic_relational_backend_command(std::path::Path::new("apps/dev_docs"), todo!());
3155/// ```
3156///
3157/// # Related
3158///
3159/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3160pub fn handle_dynamic_relational_backend_command(
3161    app_root: &Path,
3162    runtime_conf_path: Option<&Path>,
3163) -> Option<String> {
3164    dynamic_relational_backend(app_root, runtime_conf_path)
3165}
3166
3167/// Handles dynamic safe upload filename command.
3168///
3169/// # Parameters
3170///
3171/// - `raw_name`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_safe_upload_filename_command`].
3172///
3173/// # Returns
3174///
3175/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_safe_upload_filename_command`] can produce a value and [`None`] otherwise.
3176///
3177/// # Examples
3178///
3179/// ```rust,ignore
3180/// let _result = pharos_native::runtime::json_commands::handle_dynamic_safe_upload_filename_command(Some("file.txt"));
3181/// ```
3182///
3183/// # Related
3184///
3185/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3186pub fn handle_dynamic_safe_upload_filename_command(raw_name: Option<&str>) -> Option<String> {
3187    dynamic_safe_upload_filename(raw_name)
3188}
3189
3190/// Handles dynamic media disk path command.
3191///
3192/// # Parameters
3193///
3194/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_media_disk_path_command`].
3195/// - `media_url`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_media_disk_path_command`].
3196///
3197/// # Returns
3198///
3199/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_media_disk_path_command`] can produce a value and [`None`] otherwise.
3200///
3201/// # Examples
3202///
3203/// ```rust,ignore
3204/// let _result = pharos_native::runtime::json_commands::handle_dynamic_media_disk_path_command(std::path::Path::new("build/dev_docs"), todo!());
3205/// ```
3206///
3207/// # Related
3208///
3209/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3210pub fn handle_dynamic_media_disk_path_command(
3211    artifact_dir: &Path,
3212    media_url: &str,
3213) -> Option<String> {
3214    dynamic_media_disk_path(artifact_dir, media_url)
3215}
3216
3217/// Handles dynamic ensure business media tree command.
3218///
3219/// # Parameters
3220///
3221/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_ensure_business_media_tree_command`].
3222/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_ensure_business_media_tree_command`].
3223///
3224/// # Returns
3225///
3226/// Returns the computed value produced by [`crate::runtime::json_commands::handle_dynamic_ensure_business_media_tree_command`].
3227///
3228/// # Examples
3229///
3230/// ```rust,ignore
3231/// let _result = pharos_native::runtime::json_commands::handle_dynamic_ensure_business_media_tree_command(std::path::Path::new("build/dev_docs"), "demo");
3232/// ```
3233///
3234/// # Related
3235///
3236/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3237pub fn handle_dynamic_ensure_business_media_tree_command(
3238    artifact_dir: &Path,
3239    business_slug: &str,
3240) -> i32 {
3241    dynamic_ensure_business_media_tree(artifact_dir, business_slug)
3242}
3243
3244/// Handles dynamic remove media URL file command.
3245///
3246/// # Parameters
3247///
3248/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_remove_media_url_file_command`].
3249/// - `media_url`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_remove_media_url_file_command`].
3250///
3251/// # Returns
3252///
3253/// Returns the computed value produced by [`crate::runtime::json_commands::handle_dynamic_remove_media_url_file_command`].
3254///
3255/// # Examples
3256///
3257/// ```rust,ignore
3258/// let _result = pharos_native::runtime::json_commands::handle_dynamic_remove_media_url_file_command(std::path::Path::new("build/dev_docs"), todo!());
3259/// ```
3260///
3261/// # Related
3262///
3263/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3264pub fn handle_dynamic_remove_media_url_file_command(artifact_dir: &Path, media_url: &str) -> i32 {
3265    dynamic_remove_business_media_url_file(artifact_dir, media_url)
3266}
3267
3268/// Handles dynamic store uploaded media command.
3269///
3270/// # Parameters
3271///
3272/// - `artifact_dir`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3273/// - `content_type`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3274/// - `body_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3275/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3276/// - `target_url_dir`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3277/// - `fallback_filename`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`].
3278///
3279/// # Returns
3280///
3281/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_store_uploaded_media_command`] can produce a value and [`None`] otherwise.
3282///
3283/// # Examples
3284///
3285/// ```rust,ignore
3286/// let _result = pharos_native::runtime::json_commands::handle_dynamic_store_uploaded_media_command(std::path::Path::new("build/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
3287/// ```
3288///
3289/// # Related
3290///
3291/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3292pub fn handle_dynamic_store_uploaded_media_command(
3293    artifact_dir: &Path,
3294    content_type: &str,
3295    body_path: &Path,
3296    field_name: &str,
3297    target_url_dir: &str,
3298    fallback_filename: Option<&str>,
3299) -> Option<String> {
3300    dynamic_store_uploaded_media(
3301        artifact_dir,
3302        content_type,
3303        body_path,
3304        field_name,
3305        target_url_dir,
3306        fallback_filename,
3307    )
3308}
3309
3310/// Returns whether safe SQL identifier.
3311///
3312/// # Parameters
3313///
3314/// - `text`: Input consumed by [`crate::runtime::json_commands::is_safe_sql_identifier`].
3315///
3316/// # Returns
3317///
3318/// Returns `true` when the condition checked by [`crate::runtime::json_commands::is_safe_sql_identifier`] holds and `false` otherwise.
3319///
3320/// # Performance
3321///
3322/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::is_safe_sql_identifier`].
3323///
3324/// # Examples
3325///
3326/// ```rust,ignore
3327/// let _result = pharos_native::runtime::json_commands::is_safe_sql_identifier("{}");
3328/// ```
3329///
3330/// # Related
3331///
3332/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3333pub fn is_safe_sql_identifier(text: &str) -> bool {
3334    !text.is_empty()
3335        && text
3336            .chars()
3337            .all(|ch| ch.is_ascii_alphanumeric() || ch == '_')
3338}
3339
3340/// Computes a SHA-256 checksum without invoking a host utility.
3341///
3342/// # Parameters
3343///
3344/// - `value`: Input consumed by [`crate::runtime::json_commands::checksum_string`].
3345///
3346/// # Returns
3347///
3348/// Returns [`Some`] when [`crate::runtime::json_commands::checksum_string`] can produce a value and [`None`] otherwise.
3349///
3350/// # Examples
3351///
3352/// ```rust,ignore
3353/// let _result = pharos_native::runtime::json_commands::checksum_string("value");
3354/// ```
3355///
3356/// # Related
3357///
3358/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3359pub fn checksum_string(value: &str) -> Option<String> {
3360    Some(migration_sha256_text(value))
3361}
3362
3363/// Performs dynamic file signature.
3364///
3365/// # Parameters
3366///
3367/// - `path`: Input consumed by [`crate::runtime::json_commands::dynamic_file_signature`].
3368///
3369/// # Returns
3370///
3371/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_file_signature`] can produce a value and [`None`] otherwise.
3372///
3373/// # Performance
3374///
3375/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_file_signature`].
3376///
3377/// # Examples
3378///
3379/// ```rust,ignore
3380/// let _result = pharos_native::runtime::json_commands::dynamic_file_signature(std::path::Path::new("fixture.json"));
3381/// ```
3382///
3383/// # Related
3384///
3385/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3386pub fn dynamic_file_signature(path: &Path) -> Option<String> {
3387    if path.as_os_str().is_empty() {
3388        return None;
3389    }
3390    if !path.exists() {
3391        return Some("missing".to_owned());
3392    }
3393    let bytes = fs::read(path).ok()?;
3394    let mut hash = 1469598103934665603u64;
3395    for value in &bytes {
3396        hash ^= u64::from(*value);
3397        hash = hash.wrapping_mul(1099511628211);
3398    }
3399    Some(format!("{hash:016x}:{}", bytes.len()))
3400}
3401
3402/// Handles dynamic file signature command.
3403///
3404/// # Parameters
3405///
3406/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_file_signature_command`].
3407///
3408/// # Returns
3409///
3410/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_file_signature_command`] can produce a value and [`None`] otherwise.
3411///
3412/// # Examples
3413///
3414/// ```rust,ignore
3415/// let _result = pharos_native::runtime::json_commands::handle_dynamic_file_signature_command(std::path::Path::new("fixture.json"));
3416/// ```
3417///
3418/// # Related
3419///
3420/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3421pub fn handle_dynamic_file_signature_command(path: &Path) -> Option<String> {
3422    dynamic_file_signature(path)
3423}
3424
3425/// Reports declared, applied, interrupted, and live-schema migration drift.
3426///
3427/// # Parameters
3428///
3429/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_migration_drift_report`].
3430/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::dynamic_migration_drift_report`].
3431/// - `app_id`: Input consumed by [`crate::runtime::json_commands::dynamic_migration_drift_report`].
3432///
3433/// # Returns
3434///
3435/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_migration_drift_report`] can produce a value and [`None`] otherwise.
3436///
3437/// # Examples
3438///
3439/// ```rust,ignore
3440/// let _result = pharos_native::runtime::json_commands::dynamic_migration_drift_report(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
3441/// ```
3442///
3443/// # Related
3444///
3445/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3446pub fn dynamic_migration_drift_report(
3447    app_root: &Path,
3448    runtime_conf_path: Option<&Path>,
3449    app_id: Option<&str>,
3450) -> Option<Value> {
3451    super::database::dynamic_migration_drift_report(app_root, runtime_conf_path, app_id)
3452}
3453
3454/// Handles dynamic relational runtime export JSON command.
3455///
3456/// # Parameters
3457///
3458/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_export_json_command`].
3459/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_export_json_command`].
3460/// - `app_id`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_export_json_command`].
3461///
3462/// # Returns
3463///
3464/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_relational_runtime_export_json_command`] can produce a value and [`None`] otherwise.
3465///
3466/// # Examples
3467///
3468/// ```rust,ignore
3469/// let _result = pharos_native::runtime::json_commands::handle_dynamic_relational_runtime_export_json_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
3470/// ```
3471///
3472/// # Related
3473///
3474/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3475pub fn handle_dynamic_relational_runtime_export_json_command(
3476    app_root: &Path,
3477    runtime_conf_path: Option<&Path>,
3478    app_id: Option<&str>,
3479) -> Option<String> {
3480    dynamic_relational_runtime_export_json(app_root, runtime_conf_path, app_id)
3481}
3482
3483/// Handles dynamic relational runtime audit count command.
3484///
3485/// # Parameters
3486///
3487/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_audit_count_command`].
3488/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_audit_count_command`].
3489/// - `app_id`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_audit_count_command`].
3490///
3491/// # Returns
3492///
3493/// Returns [`Some`] when [`crate::runtime::json_commands::handle_dynamic_relational_runtime_audit_count_command`] can produce a value and [`None`] otherwise.
3494///
3495/// # Examples
3496///
3497/// ```rust,ignore
3498/// let _result = pharos_native::runtime::json_commands::handle_dynamic_relational_runtime_audit_count_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
3499/// ```
3500///
3501/// # Related
3502///
3503/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3504pub fn handle_dynamic_relational_runtime_audit_count_command(
3505    app_root: &Path,
3506    runtime_conf_path: Option<&Path>,
3507    app_id: Option<&str>,
3508) -> Option<String> {
3509    dynamic_relational_runtime_audit_count(app_root, runtime_conf_path, app_id)
3510}
3511
3512/// Handles dynamic relational runtime import state command.
3513///
3514/// # Parameters
3515///
3516/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3517/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3518/// - `app_id`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3519/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3520/// - `expected_audit_count`: Input consumed by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3521///
3522/// # Returns
3523///
3524/// Returns the computed value produced by [`crate::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command`].
3525///
3526/// # Examples
3527///
3528/// ```rust,ignore
3529/// let _result = pharos_native::runtime::json_commands::handle_dynamic_relational_runtime_import_state_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
3530/// ```
3531///
3532/// # Related
3533///
3534/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3535pub fn handle_dynamic_relational_runtime_import_state_command(
3536    app_root: &Path,
3537    runtime_conf_path: Option<&Path>,
3538    app_id: Option<&str>,
3539    state_path: &Path,
3540    expected_audit_count: Option<&str>,
3541) -> i32 {
3542    dynamic_relational_runtime_import_state(
3543        app_root,
3544        runtime_conf_path,
3545        app_id,
3546        state_path,
3547        expected_audit_count,
3548    )
3549}
3550
3551/// Performs file normalize runtime state.
3552///
3553/// # Parameters
3554///
3555/// - `path`: Input consumed by [`crate::runtime::json_commands::file_normalize_runtime_state`].
3556/// - `schema_value`: Input consumed by [`crate::runtime::json_commands::file_normalize_runtime_state`].
3557/// - `sections_csv`: Input consumed by [`crate::runtime::json_commands::file_normalize_runtime_state`].
3558///
3559/// # Returns
3560///
3561/// Returns [`Some`] when [`crate::runtime::json_commands::file_normalize_runtime_state`] can produce a value and [`None`] otherwise.
3562///
3563/// # Performance
3564///
3565/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::file_normalize_runtime_state`].
3566///
3567/// # Examples
3568///
3569/// ```rust,ignore
3570/// let _result = pharos_native::runtime::json_commands::file_normalize_runtime_state(std::path::Path::new("fixture.json"), todo!(), todo!());
3571/// ```
3572///
3573/// # Related
3574///
3575/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3576pub fn file_normalize_runtime_state(
3577    path: &Path,
3578    schema_value: Option<&str>,
3579    sections_csv: Option<&str>,
3580) -> Option<String> {
3581    if path.as_os_str().is_empty() {
3582        return None;
3583    }
3584    let mut root = read_json_file(path)?;
3585    let object = root.as_object_mut()?;
3586    if let Some(schema_value) = schema_value.filter(|value| !value.is_empty())
3587        && !object.contains_key("schema")
3588    {
3589        object.insert("schema".to_owned(), Value::String(schema_value.to_owned()));
3590    }
3591    if let Some(sections_csv) = sections_csv.filter(|value| !value.is_empty()) {
3592        for token in sections_csv.split(',') {
3593            let key = token.trim();
3594            if !key.is_empty() && !object.contains_key(key) {
3595                object.insert(key.to_owned(), Value::Array(Vec::new()));
3596            }
3597        }
3598    }
3599    serde_json::to_string(&root).ok()
3600}
3601
3602/// Performs request checkbox ID array JSON.
3603///
3604/// # Parameters
3605///
3606/// - `text`: Input consumed by [`crate::runtime::json_commands::request_checkbox_id_array_json`].
3607/// - `prefix`: Input consumed by [`crate::runtime::json_commands::request_checkbox_id_array_json`].
3608///
3609/// # Returns
3610///
3611/// Returns [`Some`] when [`crate::runtime::json_commands::request_checkbox_id_array_json`] can produce a value and [`None`] otherwise.
3612///
3613/// # Performance
3614///
3615/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_checkbox_id_array_json`].
3616///
3617/// # Examples
3618///
3619/// ```rust,ignore
3620/// let _result = pharos_native::runtime::json_commands::request_checkbox_id_array_json("{}", todo!());
3621/// ```
3622///
3623/// # Related
3624///
3625/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3626pub fn request_checkbox_id_array_json(text: &str, prefix: &str) -> Option<String> {
3627    if prefix.is_empty() {
3628        return None;
3629    }
3630    let mut values: Vec<i64> = Vec::new();
3631    for pair in text.split('&') {
3632        let Some((key, value)) = pair.split_once('=') else {
3633            continue;
3634        };
3635        if !key.starts_with(prefix) || value.is_empty() {
3636            continue;
3637        }
3638        let suffix = &key[prefix.len()..];
3639        if suffix.is_empty() || !suffix.chars().all(|ch| ch.is_ascii_digit()) {
3640            continue;
3641        }
3642        let Some(parsed) = value.parse::<i64>().ok() else {
3643            continue;
3644        };
3645        if !values.contains(&parsed) && values.len() < 512 {
3646            values.push(parsed);
3647        }
3648    }
3649    serde_json::to_string(&values).ok()
3650}
3651
3652/// Performs request lines to booking options JSON.
3653///
3654/// # Parameters
3655///
3656/// - `text`: Input consumed by [`crate::runtime::json_commands::request_lines_to_booking_options_json`].
3657///
3658/// # Returns
3659///
3660/// Returns [`Some`] when [`crate::runtime::json_commands::request_lines_to_booking_options_json`] can produce a value and [`None`] otherwise.
3661///
3662/// # Performance
3663///
3664/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::request_lines_to_booking_options_json`].
3665///
3666/// # Examples
3667///
3668/// ```rust,ignore
3669/// let _result = pharos_native::runtime::json_commands::request_lines_to_booking_options_json("{}");
3670/// ```
3671///
3672/// # Related
3673///
3674/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3675pub fn request_lines_to_booking_options_json(text: &str) -> Option<String> {
3676    let mut rows = Vec::new();
3677    for line in text.lines() {
3678        let trimmed = line.trim();
3679        if trimmed.is_empty() {
3680            continue;
3681        }
3682        let mut parts = trimmed.splitn(3, '|');
3683        let label = parts.next().unwrap_or_default().trim();
3684        let duration_text = parts.next().unwrap_or_default().trim();
3685        let cost = parts.next().unwrap_or_default().trim();
3686        if label.is_empty() && duration_text.is_empty() && cost.is_empty() {
3687            continue;
3688        }
3689        let duration =
3690            if !duration_text.is_empty() && duration_text.chars().all(|ch| ch.is_ascii_digit()) {
3691                duration_text.parse::<u64>().ok().unwrap_or(0)
3692            } else {
3693                0
3694            };
3695        rows.push(serde_json::json!({
3696            "label": label,
3697            "duration_minutes": duration,
3698            "cost": cost,
3699        }));
3700    }
3701    serde_json::to_string(&rows).ok()
3702}
3703
3704/// Handles request checkbox ID array JSON command.
3705///
3706/// # Parameters
3707///
3708/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_checkbox_id_array_json_command`].
3709/// - `prefix`: Input consumed by [`crate::runtime::json_commands::handle_request_checkbox_id_array_json_command`].
3710///
3711/// # Returns
3712///
3713/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_checkbox_id_array_json_command`] can produce a value and [`None`] otherwise.
3714///
3715/// # Examples
3716///
3717/// ```rust,ignore
3718/// let _result = pharos_native::runtime::json_commands::handle_request_checkbox_id_array_json_command("{}", todo!());
3719/// ```
3720///
3721/// # Related
3722///
3723/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3724pub fn handle_request_checkbox_id_array_json_command(text: &str, prefix: &str) -> Option<String> {
3725    request_checkbox_id_array_json(text, prefix)
3726}
3727
3728/// Handles request lines to booking options JSON command.
3729///
3730/// # Parameters
3731///
3732/// - `text`: Input consumed by [`crate::runtime::json_commands::handle_request_lines_to_booking_options_json_command`].
3733///
3734/// # Returns
3735///
3736/// Returns [`Some`] when [`crate::runtime::json_commands::handle_request_lines_to_booking_options_json_command`] can produce a value and [`None`] otherwise.
3737///
3738/// # Examples
3739///
3740/// ```rust,ignore
3741/// let _result = pharos_native::runtime::json_commands::handle_request_lines_to_booking_options_json_command("{}");
3742/// ```
3743///
3744/// # Related
3745///
3746/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3747pub fn handle_request_lines_to_booking_options_json_command(text: &str) -> Option<String> {
3748    request_lines_to_booking_options_json(text)
3749}
3750
3751/// Handles object merge command.
3752///
3753/// # Parameters
3754///
3755/// - `base_json`: Input consumed by [`crate::runtime::json_commands::handle_object_merge_command`].
3756/// - `overlay_json`: Input consumed by [`crate::runtime::json_commands::handle_object_merge_command`].
3757///
3758/// # Returns
3759///
3760/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_merge_command`] can produce a value and [`None`] otherwise.
3761///
3762/// # Examples
3763///
3764/// ```rust,ignore
3765/// let _result = pharos_native::runtime::json_commands::handle_object_merge_command("{}", "{}");
3766/// ```
3767///
3768/// # Related
3769///
3770/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3771pub fn handle_object_merge_command(base_json: &str, overlay_json: &str) -> Option<String> {
3772    object_merge(base_json, overlay_json)
3773}
3774
3775/// Handles object build command.
3776///
3777/// # Parameters
3778///
3779/// - `ops`: Input consumed by [`crate::runtime::json_commands::handle_object_build_command`].
3780///
3781/// # Returns
3782///
3783/// Returns [`Some`] when [`crate::runtime::json_commands::handle_object_build_command`] can produce a value and [`None`] otherwise.
3784///
3785/// # Examples
3786///
3787/// ```rust,ignore
3788/// let _result = pharos_native::runtime::json_commands::handle_object_build_command(&[]);
3789/// ```
3790///
3791/// # Related
3792///
3793/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3794pub fn handle_object_build_command(ops: &[ObjectBuildOp]) -> Option<String> {
3795    object_build(ops)
3796}
3797
3798/// Performs object merge.
3799///
3800/// # Parameters
3801///
3802/// - `base_json`: Input consumed by [`crate::runtime::json_commands::object_merge`].
3803/// - `overlay_json`: Input consumed by [`crate::runtime::json_commands::object_merge`].
3804///
3805/// # Returns
3806///
3807/// Returns [`Some`] when [`crate::runtime::json_commands::object_merge`] can produce a value and [`None`] otherwise.
3808///
3809/// # Performance
3810///
3811/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_merge`].
3812///
3813/// # Examples
3814///
3815/// ```rust,ignore
3816/// let _result = pharos_native::runtime::json_commands::object_merge("{}", "{}");
3817/// ```
3818///
3819/// # Related
3820///
3821/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3822pub fn object_merge(base_json: &str, overlay_json: &str) -> Option<String> {
3823    let mut base = serde_json::from_str::<Value>(base_json).ok()?;
3824    let overlay = serde_json::from_str::<Value>(overlay_json).ok()?;
3825    let base_obj = base.as_object_mut()?;
3826    let overlay_obj = overlay.as_object()?;
3827    for (key, value) in overlay_obj {
3828        base_obj.insert(key.clone(), value.clone());
3829    }
3830    serde_json::to_string(&base).ok()
3831}
3832
3833#[derive(Debug, Clone, Eq, PartialEq)]
3834/// Public enum `ObjectBuildOp` used by the runtime JSON-command surface.
3835///
3836/// # Variants
3837///
3838/// - `String`: Supported `ObjectBuildOp` variant.
3839/// - `Number`: Supported `ObjectBuildOp` variant.
3840/// - `Bool`: Supported `ObjectBuildOp` variant.
3841/// - `Null`: Supported `ObjectBuildOp` variant.
3842/// - `Json`: Supported `ObjectBuildOp` variant.
3843///
3844/// # Examples
3845///
3846/// ```rust,ignore
3847/// let _ = pharos_native::runtime::json_commands::ObjectBuildOp::String("title".to_owned(), "Example".to_owned());
3848/// ```
3849///
3850/// # Related
3851///
3852/// - [`crate::runtime::json_commands`] for constructors, helpers, and neighboring runtime types.
3853pub enum ObjectBuildOp {
3854    String(String, String),
3855    Number(String, i64),
3856    Bool(String, bool),
3857    Null(String),
3858    Json(String, String),
3859}
3860
3861/// Performs object build.
3862///
3863/// # Parameters
3864///
3865/// - `ops`: Input consumed by [`crate::runtime::json_commands::object_build`].
3866///
3867/// # Returns
3868///
3869/// Returns [`Some`] when [`crate::runtime::json_commands::object_build`] can produce a value and [`None`] otherwise.
3870///
3871/// # Performance
3872///
3873/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_build`].
3874///
3875/// # Examples
3876///
3877/// ```rust,ignore
3878/// let _result = pharos_native::runtime::json_commands::object_build(&[]);
3879/// ```
3880///
3881/// # Related
3882///
3883/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3884pub fn object_build(ops: &[ObjectBuildOp]) -> Option<String> {
3885    let mut object = serde_json::Map::new();
3886    for op in ops {
3887        match op {
3888            ObjectBuildOp::String(key, value) => {
3889                object.insert(key.clone(), Value::String(value.clone()));
3890            }
3891            ObjectBuildOp::Number(key, value) => {
3892                object.insert(key.clone(), serde_json::json!(*value));
3893            }
3894            ObjectBuildOp::Bool(key, value) => {
3895                object.insert(key.clone(), serde_json::json!(*value));
3896            }
3897            ObjectBuildOp::Null(key) => {
3898                object.insert(key.clone(), Value::Null);
3899            }
3900            ObjectBuildOp::Json(key, value) => {
3901                object.insert(key.clone(), serde_json::from_str::<Value>(value).ok()?);
3902            }
3903        }
3904    }
3905    serde_json::to_string(&Value::Object(object)).ok()
3906}
3907
3908/// Performs template reference contains unsafe char.
3909fn template_reference_contains_unsafe_char(text: &str) -> bool {
3910    text.bytes().any(|ch| ch < 0x20 || ch == 0x7f)
3911}
3912
3913/// Performs template reference has scheme.
3914fn template_reference_has_scheme(text: &str) -> bool {
3915    let mut chars = text.chars();
3916    let Some(first) = chars.next() else {
3917        return false;
3918    };
3919    if !first.is_ascii_alphabetic() {
3920        return false;
3921    }
3922    for ch in chars {
3923        if ch == ':' {
3924            return true;
3925        }
3926        if !(ch.is_ascii_alphanumeric() || matches!(ch, '+' | '-' | '.')) {
3927            return false;
3928        }
3929    }
3930    false
3931}
3932
3933/// Performs template path reference allowed.
3934///
3935/// # Parameters
3936///
3937/// - `text`: Input consumed by [`crate::runtime::json_commands::template_path_reference_allowed`].
3938///
3939/// # Returns
3940///
3941/// Returns `true` when the condition checked by [`crate::runtime::json_commands::template_path_reference_allowed`] holds and `false` otherwise.
3942///
3943/// # Examples
3944///
3945/// ```rust,ignore
3946/// let _result = pharos_native::runtime::json_commands::template_path_reference_allowed("{}");
3947/// ```
3948///
3949/// # Related
3950///
3951/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3952pub fn template_path_reference_allowed(text: &str) -> bool {
3953    if text.is_empty() {
3954        return true;
3955    }
3956    !template_reference_contains_unsafe_char(text) && !template_reference_has_scheme(text)
3957}
3958
3959/// Performs template URL reference allowed.
3960///
3961/// # Parameters
3962///
3963/// - `text`: Input consumed by [`crate::runtime::json_commands::template_url_reference_allowed`].
3964///
3965/// # Returns
3966///
3967/// Returns `true` when the condition checked by [`crate::runtime::json_commands::template_url_reference_allowed`] holds and `false` otherwise.
3968///
3969/// # Examples
3970///
3971/// ```rust,ignore
3972/// let _result = pharos_native::runtime::json_commands::template_url_reference_allowed("{}");
3973/// ```
3974///
3975/// # Related
3976///
3977/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
3978pub fn template_url_reference_allowed(text: &str) -> bool {
3979    if text.is_empty() {
3980        return true;
3981    }
3982    if template_reference_contains_unsafe_char(text) {
3983        return false;
3984    }
3985    if text.starts_with("https://")
3986        || text.starts_with("http://")
3987        || text.starts_with("mailto:")
3988        || text.starts_with("tel:")
3989    {
3990        return true;
3991    }
3992    !template_reference_has_scheme(text)
3993}
3994
3995/// Performs join base relative path.
3996///
3997/// # Parameters
3998///
3999/// - `base_path`: Input consumed by [`crate::runtime::json_commands::join_base_relative_path`].
4000/// - `relative_path`: Input consumed by [`crate::runtime::json_commands::join_base_relative_path`].
4001///
4002/// # Returns
4003///
4004/// Returns [`Some`] when [`crate::runtime::json_commands::join_base_relative_path`] can produce a value and [`None`] otherwise.
4005///
4006/// # Examples
4007///
4008/// ```rust,ignore
4009/// let _result = pharos_native::runtime::json_commands::join_base_relative_path("/app", "page");
4010/// ```
4011///
4012/// # Related
4013///
4014/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4015pub fn join_base_relative_path(base_path: &str, relative_path: &str) -> Option<String> {
4016    if base_path.is_empty() || relative_path.is_empty() {
4017        return None;
4018    }
4019    Some(format!("{base_path}/{relative_path}"))
4020}
4021
4022/// Renders file template.
4023///
4024/// # Parameters
4025///
4026/// - `template_file`: Input consumed by [`crate::runtime::json_commands::render_file_template`].
4027/// - `params_root`: Input consumed by [`crate::runtime::json_commands::render_file_template`].
4028///
4029/// # Returns
4030///
4031/// Returns [`Some`] when [`crate::runtime::json_commands::render_file_template`] can produce a value and [`None`] otherwise.
4032///
4033/// # Performance
4034///
4035/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::render_file_template`].
4036///
4037/// # Examples
4038///
4039/// ```rust,ignore
4040/// let _result = pharos_native::runtime::json_commands::render_file_template(std::path::Path::new("template.html"), &serde_json::json!({}));
4041/// ```
4042///
4043/// # Related
4044///
4045/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4046pub fn render_file_template(template_file: &Path, params_root: &Value) -> Option<String> {
4047    if template_file.as_os_str().is_empty() || !params_root.is_object() {
4048        return None;
4049    }
4050    let text = fs::read_to_string(template_file).ok()?;
4051    let text = if text.contains("{include:") {
4052        let root = template_file
4053            .ancestors()
4054            .find(|path| path.file_name().is_some_and(|name| name == "templates"))?
4055            .canonicalize()
4056            .ok()?;
4057        expand_template_includes(&root, &text, 0, &mut 64)?
4058    } else {
4059        text
4060    };
4061    render_template_text_with_default_kind(&text, params_root, "text")
4062}
4063
4064/// Expands app-owned HTML fragments before binding values, with bounded depth,
4065/// reads and output. Canonical paths must stay within the templates directory.
4066fn expand_template_includes(
4067    root: &Path,
4068    text: &str,
4069    depth: usize,
4070    remaining: &mut usize,
4071) -> Option<String> {
4072    const LIMIT: usize = 1024 * 1024;
4073    if depth > 16 || text.len() > LIMIT {
4074        return None;
4075    }
4076    let mut output = String::new();
4077    let mut cursor = 0;
4078    while let Some(offset) = text[cursor..].find("{include:") {
4079        let start = cursor + offset;
4080        let path_start = start + "{include:".len();
4081        let end = text[path_start..].find('}')? + path_start;
4082        let relative = Path::new(&text[path_start..end]);
4083        if !relative
4084            .components()
4085            .all(|part| matches!(part, std::path::Component::Normal(_)))
4086            || relative.extension().is_none_or(|ext| ext != "html")
4087        {
4088            return None;
4089        }
4090        *remaining = remaining.checked_sub(1)?;
4091        let path = root.join(relative).canonicalize().ok()?;
4092        if !path.starts_with(root) || fs::metadata(&path).ok()?.len() > LIMIT as u64 {
4093            return None;
4094        }
4095        let child =
4096            expand_template_includes(root, &fs::read_to_string(path).ok()?, depth + 1, remaining)?;
4097        if output
4098            .len()
4099            .checked_add(start - cursor)?
4100            .checked_add(child.len())?
4101            > LIMIT
4102        {
4103            return None;
4104        }
4105        output.push_str(&text[cursor..start]);
4106        output.push_str(&child);
4107        cursor = end + 1;
4108    }
4109    if output.len().checked_add(text.len() - cursor)? > LIMIT {
4110        return None;
4111    }
4112    output.push_str(&text[cursor..]);
4113    Some(output)
4114}
4115
4116/// Performs HTML escape text.
4117///
4118/// # Parameters
4119///
4120/// - `text`: Input consumed by [`crate::runtime::json_commands::html_escape_text`].
4121///
4122/// # Returns
4123///
4124/// Returns the computed value produced by [`crate::runtime::json_commands::html_escape_text`].
4125///
4126/// # Examples
4127///
4128/// ```rust,ignore
4129/// let _result = pharos_native::runtime::json_commands::html_escape_text("{}");
4130/// ```
4131///
4132/// # Related
4133///
4134/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4135pub fn html_escape_text(text: &str) -> String {
4136    text.replace('&', "&amp;")
4137        .replace('<', "&lt;")
4138        .replace('>', "&gt;")
4139        .replace('"', "&quot;")
4140        .replace('\'', "&#39;")
4141}
4142
4143/// Performs YAML to JSON value.
4144fn yaml_to_json_value(value: &saphyr::Yaml<'_>) -> Option<Value> {
4145    match value {
4146        saphyr::Yaml::BadValue | saphyr::Yaml::Alias(_) | saphyr::Yaml::Representation(_, _, _) => {
4147            None
4148        }
4149        saphyr::Yaml::Tagged(_, node) => yaml_to_json_value(node),
4150        saphyr::Yaml::Sequence(items) => items
4151            .iter()
4152            .map(yaml_to_json_value)
4153            .collect::<Option<Vec<_>>>()
4154            .map(Value::Array),
4155        saphyr::Yaml::Mapping(entries) => {
4156            let mut map = serde_json::Map::new();
4157            for (key, entry) in entries {
4158                let key = if let Some(text) = key.as_str() {
4159                    text.to_owned()
4160                } else if let Some(number) = key.as_integer() {
4161                    number.to_string()
4162                } else if let Some(flag) = key.as_bool() {
4163                    flag.to_string()
4164                } else {
4165                    let number = key.clone().into_floating_point()?;
4166                    number.to_string()
4167                };
4168                map.insert(key, yaml_to_json_value(entry)?);
4169            }
4170            Some(Value::Object(map))
4171        }
4172        saphyr::Yaml::Value(scalar) => match scalar {
4173            saphyr::Scalar::Null => Some(Value::Null),
4174            saphyr::Scalar::Boolean(flag) => Some(Value::Bool(*flag)),
4175            saphyr::Scalar::Integer(number) => Some(Value::Number((*number).into())),
4176            saphyr::Scalar::FloatingPoint(number) => {
4177                serde_json::Number::from_f64((*number).into()).map(Value::Number)
4178            }
4179            saphyr::Scalar::String(text) => Some(Value::String(text.to_string())),
4180        },
4181    }
4182}
4183
4184/// Reads JSON or YAML file.
4185fn read_json_or_yaml_file(path: &Path) -> Option<Value> {
4186    match path.extension().and_then(|value| value.to_str()) {
4187        Some("yml") | Some("yaml") => {
4188            let text = fs::read_to_string(path).ok()?;
4189            pharos_runtime_core::yaml::validate_unique_mapping_keys(&text).ok()?;
4190            let documents = saphyr::Yaml::load_from_str(&text).ok()?;
4191            yaml_to_json_value(&documents.into_iter().next()?)
4192        }
4193        _ => read_json_file(path),
4194    }
4195}
4196
4197/// Performs app root relative path.
4198fn app_root_relative_path(app_root: &Path, relative_path: &str) -> Option<String> {
4199    if app_root.as_os_str().is_empty() || relative_path.is_empty() {
4200        return None;
4201    }
4202    Some(app_root.join(relative_path).to_string_lossy().into_owned())
4203}
4204
4205/// Performs runtime find declared fragment relative path in directory.
4206fn runtime_find_declared_fragment_relative_path_in_directory(
4207    absolute_dir: &Path,
4208    relative_dir: &str,
4209    stem: &str,
4210    suffixes: &[&str],
4211) -> Option<String> {
4212    if absolute_dir.as_os_str().is_empty() || stem.is_empty() {
4213        return None;
4214    }
4215    let entries = fs::read_dir(absolute_dir).ok()?;
4216    for entry in entries {
4217        let entry = entry.ok()?;
4218        let path = entry.path();
4219        let file_name = entry.file_name();
4220        let file_name = file_name.to_string_lossy();
4221        if file_name == "." || file_name == ".." {
4222            continue;
4223        }
4224        let relative_child = if relative_dir.is_empty() {
4225            file_name.to_string()
4226        } else {
4227            format!("{relative_dir}/{file_name}")
4228        };
4229        if path.is_dir() {
4230            if let Some(found) = runtime_find_declared_fragment_relative_path_in_directory(
4231                &path,
4232                &relative_child,
4233                stem,
4234                suffixes,
4235            ) {
4236                return Some(found);
4237            }
4238            continue;
4239        }
4240        for suffix in suffixes {
4241            if let Some(candidate_stem) = file_name.strip_suffix(suffix)
4242                && candidate_stem == stem
4243            {
4244                return Some(relative_child);
4245            }
4246        }
4247    }
4248    None
4249}
4250
4251/// Finds one bounded page declaration by its explicit `page_id` field.
4252fn declared_page_relative_path_by_id(app_root: &Path, page_id: &str) -> Option<String> {
4253    const MAX_PAGE_DECLARATION_FILES: usize = 4_096;
4254    const MAX_PAGE_DECLARATION_DEPTH: usize = 32;
4255    let templates_root = app_root.join("templates");
4256    let mut directories = vec![(templates_root, 0_usize)];
4257    let mut matching_path = None;
4258    let mut visited_files = 0_usize;
4259
4260    while let Some((directory, depth)) = directories.pop() {
4261        if depth > MAX_PAGE_DECLARATION_DEPTH {
4262            return None;
4263        }
4264        let mut entries = fs::read_dir(&directory)
4265            .ok()?
4266            .collect::<Result<Vec<_>, _>>()
4267            .ok()?;
4268        entries.sort_by_key(|entry| entry.file_name());
4269        for entry in entries {
4270            let path = entry.path();
4271            let metadata = fs::symlink_metadata(&path).ok()?;
4272            if metadata.file_type().is_symlink() {
4273                return None;
4274            }
4275            if metadata.is_dir() {
4276                directories.push((path, depth + 1));
4277                continue;
4278            }
4279            if !metadata.is_file() {
4280                continue;
4281            }
4282            visited_files += 1;
4283            if visited_files > MAX_PAGE_DECLARATION_FILES {
4284                return None;
4285            }
4286            let file_name = path.file_name()?.to_str()?;
4287            if ![".page.json", ".page.yml", ".page.yaml"]
4288                .iter()
4289                .any(|suffix| file_name.ends_with(suffix))
4290            {
4291                continue;
4292            }
4293            let declaration = read_json_or_yaml_file(&path)?;
4294            if declaration.get("page_id").and_then(Value::as_str) != Some(page_id) {
4295                continue;
4296            }
4297            let relative = path
4298                .strip_prefix(app_root)
4299                .ok()?
4300                .to_string_lossy()
4301                .into_owned();
4302            if matching_path.replace(relative).is_some() {
4303                return None;
4304            }
4305        }
4306    }
4307    matching_path
4308}
4309
4310/// Resolves a page declaration by conventional filename or explicit `page_id`.
4311///
4312/// # Parameters
4313///
4314/// - `app_root`: Input consumed by [`crate::runtime::json_commands::declared_page_relative_path`].
4315/// - `page_id`: Input consumed by [`crate::runtime::json_commands::declared_page_relative_path`].
4316///
4317/// # Returns
4318///
4319/// Returns [`Some`] when [`crate::runtime::json_commands::declared_page_relative_path`] can produce a value and [`None`] otherwise.
4320///
4321/// # Performance
4322///
4323/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::declared_page_relative_path`].
4324///
4325/// # Examples
4326///
4327/// ```rust,ignore
4328/// let _result = pharos_native::runtime::json_commands::declared_page_relative_path(std::path::Path::new("apps/dev_docs"), "home");
4329/// ```
4330///
4331/// # Related
4332///
4333/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4334pub fn declared_page_relative_path(app_root: &Path, page_id: &str) -> Option<String> {
4335    if app_root.as_os_str().is_empty() || page_id.is_empty() {
4336        return None;
4337    }
4338    let direct_patterns = [
4339        format!("templates/{page_id}.page.json"),
4340        format!("templates/{page_id}.page.yml"),
4341        format!("templates/{page_id}/{page_id}.page.json"),
4342        format!("templates/{page_id}/{page_id}.page.yml"),
4343    ];
4344    for relative in direct_patterns {
4345        if app_root.join(&relative).exists() {
4346            return Some(relative);
4347        }
4348    }
4349    runtime_find_declared_fragment_relative_path_in_directory(
4350        &app_root.join("templates"),
4351        "templates",
4352        &format!("{page_id}.page"),
4353        &[".json", ".yml", ".yaml"],
4354    )
4355    .or_else(|| declared_page_relative_path_by_id(app_root, page_id))
4356}
4357
4358/// Performs template declared page contract.
4359///
4360/// # Parameters
4361///
4362/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_declared_page_contract`].
4363/// - `page_id`: Input consumed by [`crate::runtime::json_commands::template_declared_page_contract`].
4364///
4365/// # Returns
4366///
4367/// Returns [`Some`] when [`crate::runtime::json_commands::template_declared_page_contract`] can produce a value and [`None`] otherwise.
4368///
4369/// # Examples
4370///
4371/// ```rust,ignore
4372/// let _result = pharos_native::runtime::json_commands::template_declared_page_contract(std::path::Path::new("apps/dev_docs"), "home");
4373/// ```
4374///
4375/// # Related
4376///
4377/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4378pub fn template_declared_page_contract(app_root: &Path, page_id: &str) -> Option<String> {
4379    let relative_path = declared_page_relative_path(app_root, page_id)?;
4380    let spec_path = app_root.join(&relative_path);
4381    let root = read_json_or_yaml_file(&spec_path)?;
4382    let template_rel = root
4383        .get("template_file")
4384        .and_then(Value::as_str)
4385        .unwrap_or_default();
4386    let title = root
4387        .get("title")
4388        .and_then(Value::as_str)
4389        .unwrap_or_default();
4390    let layout_id = root
4391        .get("layout_id")
4392        .and_then(Value::as_str)
4393        .unwrap_or_default();
4394    serde_json::to_string(&serde_json::json!({
4395        "spec_path": spec_path.to_string_lossy(),
4396        "template_path": app_root.join(template_rel).to_string_lossy(),
4397        "title": title,
4398        "layout_id": layout_id,
4399    }))
4400    .ok()
4401}
4402
4403/// Performs template render path.
4404///
4405/// # Parameters
4406///
4407/// - `template_path`: Input consumed by [`crate::runtime::json_commands::template_render_path`].
4408/// - `params_root`: Input consumed by [`crate::runtime::json_commands::template_render_path`].
4409///
4410/// # Returns
4411///
4412/// Returns [`Some`] when [`crate::runtime::json_commands::template_render_path`] can produce a value and [`None`] otherwise.
4413///
4414/// # Performance
4415///
4416/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::template_render_path`].
4417///
4418/// # Examples
4419///
4420/// ```rust,ignore
4421/// let _result = pharos_native::runtime::json_commands::template_render_path("template.html", &serde_json::json!({}));
4422/// ```
4423///
4424/// # Related
4425///
4426/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4427pub fn template_render_path(template_path: &str, params_root: &Value) -> Option<String> {
4428    if template_path.is_empty() || !params_root.is_object() {
4429        return None;
4430    }
4431    let params = params_root.as_object()?;
4432    let mut out = String::with_capacity(template_path.len() + 32);
4433    let mut cursor = 0usize;
4434    while let Some(relative_open) = template_path[cursor..].find('{') {
4435        let open = cursor + relative_open;
4436        out.push_str(&template_path[cursor..open]);
4437        let key_start = open + 1;
4438        let relative_close = template_path[key_start..].find('}')?;
4439        let close = key_start + relative_close;
4440        let key = &template_path[key_start..close];
4441        let value = params.get(key)?;
4442        let rendered = match value {
4443            Value::String(text) => text.clone(),
4444            Value::Number(number) => number.to_string(),
4445            Value::Bool(flag) => flag.to_string(),
4446            Value::Null => String::new(),
4447            _ => serde_json::to_string(value).ok()?,
4448        };
4449        if !template_path_reference_allowed(&rendered) {
4450            return None;
4451        }
4452        out.push_str(&rendered);
4453        cursor = close + 1;
4454    }
4455    out.push_str(&template_path[cursor..]);
4456    Some(out)
4457}
4458
4459/// Performs template render file.
4460///
4461/// # Parameters
4462///
4463/// - `template_file`: Input consumed by [`crate::runtime::json_commands::template_render_file`].
4464/// - `params_root`: Input consumed by [`crate::runtime::json_commands::template_render_file`].
4465///
4466/// # Returns
4467///
4468/// Returns [`Some`] when [`crate::runtime::json_commands::template_render_file`] can produce a value and [`None`] otherwise.
4469///
4470/// # Examples
4471///
4472/// ```rust,ignore
4473/// let _result = pharos_native::runtime::json_commands::template_render_file(std::path::Path::new("template.html"), &serde_json::json!({}));
4474/// ```
4475///
4476/// # Related
4477///
4478/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4479pub fn template_render_file(template_file: &Path, params_root: &Value) -> Option<String> {
4480    render_file_template(template_file, params_root)
4481}
4482
4483/// Handles template render path command.
4484///
4485/// # Parameters
4486///
4487/// - `template_path`: Input consumed by [`crate::runtime::json_commands::handle_template_render_path_command`].
4488/// - `params_root`: Input consumed by [`crate::runtime::json_commands::handle_template_render_path_command`].
4489///
4490/// # Returns
4491///
4492/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_render_path_command`] can produce a value and [`None`] otherwise.
4493///
4494/// # Examples
4495///
4496/// ```rust,ignore
4497/// let _result = pharos_native::runtime::json_commands::handle_template_render_path_command("template.html", &serde_json::json!({}));
4498/// ```
4499///
4500/// # Related
4501///
4502/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4503pub fn handle_template_render_path_command(
4504    template_path: &str,
4505    params_root: &Value,
4506) -> Option<String> {
4507    template_render_path(template_path, params_root)
4508}
4509
4510/// Handles template render file command.
4511///
4512/// # Parameters
4513///
4514/// - `template_file`: Input consumed by [`crate::runtime::json_commands::handle_template_render_file_command`].
4515/// - `params_root`: Input consumed by [`crate::runtime::json_commands::handle_template_render_file_command`].
4516///
4517/// # Returns
4518///
4519/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_render_file_command`] can produce a value and [`None`] otherwise.
4520///
4521/// # Examples
4522///
4523/// ```rust,ignore
4524/// let _result = pharos_native::runtime::json_commands::handle_template_render_file_command(std::path::Path::new("template.html"), &serde_json::json!({}));
4525/// ```
4526///
4527/// # Related
4528///
4529/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4530pub fn handle_template_render_file_command(
4531    template_file: &Path,
4532    params_root: &Value,
4533) -> Option<String> {
4534    template_render_file(template_file, params_root)
4535}
4536
4537/// Performs template declared fragment path.
4538///
4539/// # Parameters
4540///
4541/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_declared_fragment_path`].
4542/// - `fragment_id`: Input consumed by [`crate::runtime::json_commands::template_declared_fragment_path`].
4543///
4544/// # Returns
4545///
4546/// Returns [`Some`] when [`crate::runtime::json_commands::template_declared_fragment_path`] can produce a value and [`None`] otherwise.
4547///
4548/// # Examples
4549///
4550/// ```rust,ignore
4551/// let _result = pharos_native::runtime::json_commands::template_declared_fragment_path(std::path::Path::new("apps/dev_docs"), "header");
4552/// ```
4553///
4554/// # Related
4555///
4556/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4557pub fn template_declared_fragment_path(app_root: &Path, fragment_id: &str) -> Option<String> {
4558    if app_root.as_os_str().is_empty() || fragment_id.is_empty() {
4559        return None;
4560    }
4561    app_root_relative_path(
4562        app_root,
4563        &runtime_find_declared_fragment_relative_path_in_directory(
4564            &app_root.join("templates"),
4565            "templates",
4566            fragment_id,
4567            &[".html"],
4568        )?,
4569    )
4570}
4571
4572/// Performs template apply base path.
4573///
4574/// # Parameters
4575///
4576/// - `html`: Input consumed by [`crate::runtime::json_commands::template_apply_base_path`].
4577/// - `base_path`: Input consumed by [`crate::runtime::json_commands::template_apply_base_path`].
4578///
4579/// # Returns
4580///
4581/// Returns [`Some`] when [`crate::runtime::json_commands::template_apply_base_path`] can produce a value and [`None`] otherwise.
4582///
4583/// # Performance
4584///
4585/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::template_apply_base_path`].
4586///
4587/// # Examples
4588///
4589/// ```rust,ignore
4590/// let _result = pharos_native::runtime::json_commands::template_apply_base_path(todo!(), "/app");
4591/// ```
4592///
4593/// # Related
4594///
4595/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4596pub fn template_apply_base_path(html: &str, base_path: Option<&str>) -> Option<String> {
4597    let base_path = base_path.unwrap_or("");
4598    if base_path.is_empty() || base_path == "/" {
4599        return Some(html.to_owned());
4600    }
4601    let prefixes = [
4602        "href=\"/",
4603        "src=\"/",
4604        "action=\"/",
4605        "formaction=\"/",
4606        "hx-post=\"/",
4607        "hx-get=\"/",
4608        "hx-put=\"/",
4609        "hx-delete=\"/",
4610        "value=\"/",
4611    ];
4612    let mut out = String::with_capacity(html.len() + 64);
4613    let mut index = 0usize;
4614    while index < html.len() {
4615        let mut matched = false;
4616        for prefix in prefixes {
4617            if html[index..].starts_with(prefix) {
4618                let suffix_index = index + prefix.len() - 1;
4619                let already_scoped = html[suffix_index..].starts_with(base_path)
4620                    && matches!(
4621                        html[suffix_index + base_path.len()..].chars().next(),
4622                        Some('/') | Some('"') | None
4623                    );
4624                if already_scoped {
4625                    out.push_str(prefix);
4626                } else {
4627                    out.push_str(&prefix[..prefix.len() - 1]);
4628                    out.push_str(base_path);
4629                    out.push('/');
4630                }
4631                index += prefix.len();
4632                matched = true;
4633                break;
4634            }
4635        }
4636        if matched {
4637            continue;
4638        }
4639        out.push(html[index..].chars().next()?);
4640        index += html[index..].chars().next()?.len_utf8();
4641    }
4642    Some(out)
4643}
4644
4645/// Renders fragment with params.
4646fn render_fragment_with_params(
4647    app_root: &Path,
4648    relative_path: &str,
4649    params: serde_json::Map<String, Value>,
4650) -> Option<String> {
4651    generated::render_generated_admin_fragment_from_value_runtime(app_root, relative_path, &params)
4652}
4653
4654fn app_navigation_text(app_root: &Path, item_id: &str) -> Option<(String, String)> {
4655    let manifest = read_json_or_yaml_file(&app_root.join("pharos.app.json"))
4656        .or_else(|| read_json_or_yaml_file(&app_root.join("pharos.app.yml")))
4657        .or_else(|| read_json_or_yaml_file(&app_root.join("pharos.app.yaml")))?;
4658    let items = manifest
4659        .get("ui")
4660        .and_then(|ui| ui.get("navigation"))
4661        .and_then(Value::as_array)?;
4662    let item = items
4663        .iter()
4664        .find(|item| json_string(item, "item_id") == Some(item_id))?;
4665    let label = json_string(item, "label")?.to_owned();
4666    let title = json_string(item, "title")
4667        .map(ToOwned::to_owned)
4668        .unwrap_or_else(|| label.clone());
4669    Some((label, title))
4670}
4671
4672/// Renders error alert HTML.
4673fn render_error_alert_html(app_root: &Path, message: &str) -> Option<String> {
4674    if message.is_empty() {
4675        return Some(String::new());
4676    }
4677    render_fragment_with_params(
4678        app_root,
4679        "templates/shared/fragments/error_alert.html",
4680        serde_json::Map::from_iter([("message".to_owned(), Value::String(message.to_owned()))]),
4681    )
4682    .or_else(|| {
4683        Some(format!(
4684            "<p class=\"error-message\" role=\"alert\">{}</p>",
4685            html_escape_text(message)
4686        ))
4687    })
4688}
4689
4690/// Renders hidden next input HTML inner.
4691fn render_hidden_next_input_html_inner(app_root: &Path, next_path: &str) -> Option<String> {
4692    if next_path.is_empty() {
4693        return Some(String::new());
4694    }
4695    render_fragment_with_params(
4696        app_root,
4697        "templates/shared/fragments/ui_hidden_input.html",
4698        Map::from_iter([
4699            ("id".to_owned(), Value::String("next".to_owned())),
4700            ("name".to_owned(), Value::String("next".to_owned())),
4701            ("value".to_owned(), Value::String(next_path.to_owned())),
4702            ("attributes_html".to_owned(), Value::String(String::new())),
4703        ]),
4704    )
4705    .or_else(|| {
4706        Some(format!(
4707            "<input type=\"hidden\" name=\"next\" value=\"{}\">",
4708            html_escape_text(next_path)
4709        ))
4710    })
4711}
4712
4713/// Performs template page params JSON.
4714fn template_page_params_json(
4715    error_html: &str,
4716    next_input: &str,
4717    login_action_path: &str,
4718    account_type_options_html: &str,
4719    no_email_access_html: &str,
4720    reset_post_path: &str,
4721    invite_email: &str,
4722    invite_path: &str,
4723    return_path: &str,
4724    invite_kind: &str,
4725    target_html: &str,
4726    form_action: &str,
4727) -> Option<String> {
4728    serde_json::to_string(&serde_json::json!({
4729        "error_html": error_html,
4730        "next_input": next_input,
4731        "login_action_path": login_action_path,
4732        "account_type_options_html": account_type_options_html,
4733        "no_email_access_html": no_email_access_html,
4734        "reset_post_path": reset_post_path,
4735        "invite_email": invite_email,
4736        "invite_path": invite_path,
4737        "return_path": return_path,
4738        "invite_kind": invite_kind,
4739        "target_html": target_html,
4740        "form_action": form_action,
4741    }))
4742    .ok()
4743}
4744
4745/// Renders the shared inline error fragment used by declarative form pages.
4746///
4747/// # Parameters
4748///
4749/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_error_alert_html`].
4750/// - `message`: Input consumed by [`crate::runtime::json_commands::template_error_alert_html`].
4751///
4752/// # Returns
4753///
4754/// Returns [`Some`] when [`crate::runtime::json_commands::template_error_alert_html`] can produce a value and [`None`] otherwise.
4755///
4756/// # Examples
4757///
4758/// ```rust,ignore
4759/// let _result = pharos_native::runtime::json_commands::template_error_alert_html(std::path::Path::new("apps/dev_docs"), "example");
4760/// ```
4761///
4762/// # Related
4763///
4764/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4765pub fn template_error_alert_html(app_root: &Path, message: &str) -> Option<String> {
4766    render_error_alert_html(app_root, message)
4767}
4768
4769/// Performs template login page JSON.
4770///
4771/// # Parameters
4772///
4773/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_login_page_json`].
4774/// - `error_message`: Input consumed by [`crate::runtime::json_commands::template_login_page_json`].
4775/// - `next_path`: Input consumed by [`crate::runtime::json_commands::template_login_page_json`].
4776///
4777/// # Returns
4778///
4779/// Returns [`Some`] when [`crate::runtime::json_commands::template_login_page_json`] can produce a value and [`None`] otherwise.
4780///
4781/// # Examples
4782///
4783/// ```rust,ignore
4784/// let _result = pharos_native::runtime::json_commands::template_login_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
4785/// ```
4786///
4787/// # Related
4788///
4789/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4790pub fn template_login_page_json(
4791    app_root: &Path,
4792    error_message: Option<&str>,
4793    next_path: Option<&str>,
4794) -> Option<String> {
4795    let login_action_path = crate::config::app_local_conf_path(app_root)
4796        .and_then(|path| crate::config::dynamic_config_lookup_raw(&path, "base_path"))
4797        .filter(|value| value.starts_with('/') && !value.contains(['\r', '\n']))
4798        .filter(|value| value != "/")
4799        .map(|base_path| format!("{}/accounts/login/", base_path.trim_end_matches('/')))
4800        .unwrap_or_else(|| "/accounts/login/".to_owned());
4801    template_page_params_json(
4802        &render_error_alert_html(app_root, error_message.unwrap_or_default())?,
4803        &render_hidden_next_input_html_inner(app_root, next_path.unwrap_or_default())?,
4804        &login_action_path,
4805        "",
4806        "",
4807        "",
4808        "",
4809        "",
4810        "",
4811        "",
4812        "",
4813        "",
4814    )
4815}
4816
4817/// Performs template register page JSON.
4818///
4819/// # Parameters
4820///
4821/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_register_page_json`].
4822/// - `error_message`: Input consumed by [`crate::runtime::json_commands::template_register_page_json`].
4823/// - `next_path`: Input consumed by [`crate::runtime::json_commands::template_register_page_json`].
4824/// - `account_type_options_html`: Input consumed by [`crate::runtime::json_commands::template_register_page_json`].
4825///
4826/// # Returns
4827///
4828/// Returns [`Some`] when [`crate::runtime::json_commands::template_register_page_json`] can produce a value and [`None`] otherwise.
4829///
4830/// # Examples
4831///
4832/// ```rust,ignore
4833/// let _result = pharos_native::runtime::json_commands::template_register_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
4834/// ```
4835///
4836/// # Related
4837///
4838/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4839pub fn template_register_page_json(
4840    app_root: &Path,
4841    error_message: Option<&str>,
4842    next_path: Option<&str>,
4843    account_type_options_html: Option<&str>,
4844) -> Option<String> {
4845    template_page_params_json(
4846        &render_error_alert_html(app_root, error_message.unwrap_or_default())?,
4847        &render_hidden_next_input_html_inner(app_root, next_path.unwrap_or_default())?,
4848        "",
4849        account_type_options_html.unwrap_or_default(),
4850        "",
4851        "",
4852        "",
4853        "",
4854        "",
4855        "",
4856        "",
4857        "",
4858    )
4859}
4860
4861/// Performs template password reset request page JSON.
4862///
4863/// # Parameters
4864///
4865/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_password_reset_request_page_json`].
4866/// - `error_message`: Input consumed by [`crate::runtime::json_commands::template_password_reset_request_page_json`].
4867///
4868/// # Returns
4869///
4870/// Returns [`Some`] when [`crate::runtime::json_commands::template_password_reset_request_page_json`] can produce a value and [`None`] otherwise.
4871///
4872/// # Examples
4873///
4874/// ```rust,ignore
4875/// let _result = pharos_native::runtime::json_commands::template_password_reset_request_page_json(std::path::Path::new("apps/dev_docs"), todo!());
4876/// ```
4877///
4878/// # Related
4879///
4880/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4881pub fn template_password_reset_request_page_json(
4882    app_root: &Path,
4883    error_message: Option<&str>,
4884) -> Option<String> {
4885    template_page_params_json(
4886        &render_error_alert_html(app_root, error_message.unwrap_or_default())?,
4887        "",
4888        "",
4889        "",
4890        "",
4891        "",
4892        "",
4893        "",
4894        "",
4895        "",
4896        "",
4897        "",
4898    )
4899}
4900
4901/// Performs template password reset sent page JSON.
4902///
4903/// # Parameters
4904///
4905/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_password_reset_sent_page_json`].
4906/// - `preview_path`: Input consumed by [`crate::runtime::json_commands::template_password_reset_sent_page_json`].
4907///
4908/// # Returns
4909///
4910/// Returns [`Some`] when [`crate::runtime::json_commands::template_password_reset_sent_page_json`] can produce a value and [`None`] otherwise.
4911///
4912/// # Examples
4913///
4914/// ```rust,ignore
4915/// let _result = pharos_native::runtime::json_commands::template_password_reset_sent_page_json(std::path::Path::new("apps/dev_docs"), todo!());
4916/// ```
4917///
4918/// # Related
4919///
4920/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4921pub fn template_password_reset_sent_page_json(
4922    app_root: &Path,
4923    preview_path: Option<&str>,
4924) -> Option<String> {
4925    let preview_path = preview_path.unwrap_or_default();
4926    if preview_path.is_empty() {
4927        return template_page_params_json("", "", "", "", "", "", "", "", "", "", "", "");
4928    }
4929    let no_email_access_html = render_fragment_with_params(
4930        app_root,
4931        "templates/shared/fragments/no_email_access_link.html",
4932        serde_json::Map::from_iter([
4933            (
4934                "intro_text".to_owned(),
4935                Value::String(
4936                    "Email delivery is unavailable. Use this local access link:".to_owned(),
4937                ),
4938            ),
4939            (
4940                "href_path".to_owned(),
4941                Value::String(preview_path.to_owned()),
4942            ),
4943            (
4944                "access_path".to_owned(),
4945                Value::String(preview_path.to_owned()),
4946            ),
4947        ]),
4948    )?;
4949    template_page_params_json(
4950        "",
4951        "",
4952        "",
4953        "",
4954        &no_email_access_html,
4955        "",
4956        "",
4957        "",
4958        "",
4959        "",
4960        "",
4961        "",
4962    )
4963}
4964
4965/// Performs template password reset complete page JSON.
4966///
4967/// # Parameters
4968///
4969/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_password_reset_complete_page_json`].
4970/// - `error_message`: Input consumed by [`crate::runtime::json_commands::template_password_reset_complete_page_json`].
4971/// - `reset_post_path`: Input consumed by [`crate::runtime::json_commands::template_password_reset_complete_page_json`].
4972///
4973/// # Returns
4974///
4975/// Returns [`Some`] when [`crate::runtime::json_commands::template_password_reset_complete_page_json`] can produce a value and [`None`] otherwise.
4976///
4977/// # Examples
4978///
4979/// ```rust,ignore
4980/// let _result = pharos_native::runtime::json_commands::template_password_reset_complete_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
4981/// ```
4982///
4983/// # Related
4984///
4985/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
4986pub fn template_password_reset_complete_page_json(
4987    app_root: &Path,
4988    error_message: Option<&str>,
4989    reset_post_path: Option<&str>,
4990) -> Option<String> {
4991    template_page_params_json(
4992        &render_error_alert_html(app_root, error_message.unwrap_or_default())?,
4993        "",
4994        "",
4995        "",
4996        "",
4997        &html_escape_text(reset_post_path.unwrap_or_default()),
4998        "",
4999        "",
5000        "",
5001        "",
5002        "",
5003        "",
5004    )
5005}
5006
5007/// Performs template invite created page JSON.
5008///
5009/// # Parameters
5010///
5011/// - `invite_email`: Input consumed by [`crate::runtime::json_commands::template_invite_created_page_json`].
5012/// - `invite_path`: Input consumed by [`crate::runtime::json_commands::template_invite_created_page_json`].
5013/// - `return_path`: Input consumed by [`crate::runtime::json_commands::template_invite_created_page_json`].
5014///
5015/// # Returns
5016///
5017/// Returns [`Some`] when [`crate::runtime::json_commands::template_invite_created_page_json`] can produce a value and [`None`] otherwise.
5018///
5019/// # Examples
5020///
5021/// ```rust,ignore
5022/// let _result = pharos_native::runtime::json_commands::template_invite_created_page_json(todo!(), todo!(), todo!());
5023/// ```
5024///
5025/// # Related
5026///
5027/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5028pub fn template_invite_created_page_json(
5029    invite_email: Option<&str>,
5030    invite_path: Option<&str>,
5031    return_path: Option<&str>,
5032) -> Option<String> {
5033    template_page_params_json(
5034        "",
5035        "",
5036        "",
5037        "",
5038        "",
5039        "",
5040        &html_escape_text(invite_email.unwrap_or_default()),
5041        &html_escape_text(invite_path.unwrap_or_default()),
5042        &html_escape_text(return_path.unwrap_or_default()),
5043        "",
5044        "",
5045        "",
5046    )
5047}
5048
5049/// Performs template invite accept page JSON.
5050///
5051/// # Parameters
5052///
5053/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5054/// - `invite_kind`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5055/// - `target_business_name`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5056/// - `error_message`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5057/// - `invite_email`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5058/// - `form_action`: Input consumed by [`crate::runtime::json_commands::template_invite_accept_page_json`].
5059///
5060/// # Returns
5061///
5062/// Returns [`Some`] when [`crate::runtime::json_commands::template_invite_accept_page_json`] can produce a value and [`None`] otherwise.
5063///
5064/// # Examples
5065///
5066/// ```rust,ignore
5067/// let _result = pharos_native::runtime::json_commands::template_invite_accept_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
5068/// ```
5069///
5070/// # Related
5071///
5072/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5073pub fn template_invite_accept_page_json(
5074    app_root: &Path,
5075    invite_kind: Option<&str>,
5076    target_business_name: Option<&str>,
5077    error_message: Option<&str>,
5078    invite_email: Option<&str>,
5079    form_action: Option<&str>,
5080) -> Option<String> {
5081    let target_html = if let Some(target_business_name) =
5082        target_business_name.filter(|value| !value.is_empty())
5083    {
5084        render_fragment_with_params(
5085            app_root,
5086            "templates/shared/fragments/invite_target.html",
5087            serde_json::Map::from_iter([(
5088                "business_name".to_owned(),
5089                Value::String(target_business_name.to_owned()),
5090            )]),
5091        )?
5092    } else {
5093        String::new()
5094    };
5095    template_page_params_json(
5096        &render_error_alert_html(app_root, error_message.unwrap_or_default())?,
5097        "",
5098        "",
5099        "",
5100        "",
5101        "",
5102        &html_escape_text(invite_email.unwrap_or_default()),
5103        "",
5104        "",
5105        &html_escape_text(invite_kind.unwrap_or("account_invite")),
5106        &target_html,
5107        &html_escape_text(form_action.unwrap_or_default()),
5108    )
5109}
5110
5111/// Renders select fragment.
5112fn render_select_fragment(
5113    app_root: &Path,
5114    relative_path: &str,
5115    value: &str,
5116    selected: bool,
5117    label: &str,
5118) -> Option<String> {
5119    render_fragment_with_params(
5120        app_root,
5121        relative_path,
5122        serde_json::Map::from_iter([
5123            ("option_value".to_owned(), Value::String(value.to_owned())),
5124            (
5125                "selected_attr".to_owned(),
5126                Value::String(if selected { " selected" } else { "" }.to_owned()),
5127            ),
5128            ("option_label".to_owned(), Value::String(label.to_owned())),
5129        ]),
5130    )
5131}
5132
5133/// Builds layout page params JSON.
5134fn build_layout_page_params_json(
5135    app_root: &Path,
5136    layout_id: Option<&str>,
5137    title: &str,
5138    body: &str,
5139    current_lang: Option<&str>,
5140    current_request_target: Option<&str>,
5141    has_user: bool,
5142    managed_business_count: i64,
5143) -> Option<String> {
5144    let effective_layout_id = layout_id
5145        .filter(|value| !value.is_empty())
5146        .unwrap_or("default_shell");
5147    let resolved_lang = current_lang
5148        .filter(|value| !value.is_empty())
5149        .unwrap_or("en");
5150    let (nav_home_path, nav_primary, nav_account): (String, String, String);
5151
5152    let languages = [
5153        ("en", "English"),
5154        ("ja", "日本語"),
5155        ("es", "Español"),
5156        ("fr", "Français"),
5157        ("de", "Deutsch"),
5158        ("pt", "Português"),
5159    ];
5160    let mut language_options_html = String::new();
5161    for (code, label) in languages {
5162        language_options_html.push_str(&render_select_fragment(
5163            app_root,
5164            "templates/layout/fragments/language_option.html",
5165            code,
5166            resolved_lang == code,
5167            label,
5168        )?);
5169    }
5170    let language_select_ui_html = render_fragment_with_params(
5171        app_root,
5172        "templates/shared/fragments/ui_select.html",
5173        serde_json::Map::from_iter([
5174            ("id".to_owned(), Value::String("language-select".to_owned())),
5175            ("name".to_owned(), Value::String("language".to_owned())),
5176            ("label".to_owned(), Value::String("Language".to_owned())),
5177            (
5178                "label_class".to_owned(),
5179                Value::String("sr-only".to_owned()),
5180            ),
5181            (
5182                "class_name".to_owned(),
5183                Value::String("form-control".to_owned()),
5184            ),
5185            ("attributes_html".to_owned(), Value::String(String::new())),
5186            (
5187                "options_html".to_owned(),
5188                Value::String(language_options_html),
5189            ),
5190            ("help_html".to_owned(), Value::String(String::new())),
5191        ]),
5192    )?;
5193    let language_form_html = render_fragment_with_params(
5194        app_root,
5195        "templates/layout/fragments/language_form.html",
5196        serde_json::Map::from_iter([
5197            (
5198                "current_request_target".to_owned(),
5199                Value::String(current_request_target.unwrap_or("/").to_owned()),
5200            ),
5201            (
5202                "language_select_ui_html".to_owned(),
5203                Value::String(language_select_ui_html),
5204            ),
5205        ]),
5206    )?;
5207
5208    if has_user {
5209        let mut resolved_nav_home_path = "/".to_owned();
5210        let nav_primary_value: String;
5211        if effective_layout_id == "architect_shell" {
5212            let (home_label, home_title) = app_navigation_text(app_root, "home")?;
5213            let home_link_html = render_fragment_with_params(
5214                app_root,
5215                "templates/layout/fragments/nav_link.html",
5216                serde_json::Map::from_iter([
5217                    ("link_path".to_owned(), Value::String("/".to_owned())),
5218                    ("link_label".to_owned(), Value::String(home_label)),
5219                    ("link_title".to_owned(), Value::String(home_title)),
5220                    (
5221                        "class_name".to_owned(),
5222                        Value::String("nav-icon-button architect-nav-home-link".to_owned()),
5223                    ),
5224                    (
5225                        "attributes_html".to_owned(),
5226                        Value::String(" data-pharos-nav=\"architect-main\"".to_owned()),
5227                    ),
5228                ]),
5229            )?;
5230            let (file_label, file_title) = app_navigation_text(app_root, "file")?;
5231            let file_link_html = render_fragment_with_params(
5232                app_root,
5233                "templates/layout/fragments/nav_link.html",
5234                serde_json::Map::from_iter([
5235                    ("link_path".to_owned(), Value::String("/editor".to_owned())),
5236                    ("link_label".to_owned(), Value::String(file_label)),
5237                    ("link_title".to_owned(), Value::String(file_title)),
5238                    (
5239                        "class_name".to_owned(),
5240                        Value::String("nav-icon-button architect-nav-file-link".to_owned()),
5241                    ),
5242                    (
5243                        "attributes_html".to_owned(),
5244                        Value::String(" data-pharos-nav=\"architect-main\"".to_owned()),
5245                    ),
5246                ]),
5247            )?;
5248            let settings_link_html = if managed_business_count > 0 {
5249                let (settings_label, settings_title) = app_navigation_text(app_root, "settings")?;
5250                render_fragment_with_params(
5251                    app_root,
5252                    "templates/layout/fragments/nav_link.html",
5253                    serde_json::Map::from_iter([
5254                        (
5255                            "link_path".to_owned(),
5256                            Value::String("/settings".to_owned()),
5257                        ),
5258                        ("link_label".to_owned(), Value::String(settings_label)),
5259                        ("link_title".to_owned(), Value::String(settings_title)),
5260                        (
5261                            "class_name".to_owned(),
5262                            Value::String("nav-icon-button architect-nav-settings-link".to_owned()),
5263                        ),
5264                        (
5265                            "attributes_html".to_owned(),
5266                            Value::String(" data-pharos-nav=\"architect-main\"".to_owned()),
5267                        ),
5268                    ]),
5269                )?
5270            } else {
5271                String::new()
5272            };
5273            let logout_button_ui_html = render_fragment_with_params(
5274                app_root,
5275                "templates/layout/fragments/nav_logout_button.html",
5276                serde_json::Map::new(),
5277            )?;
5278            let logout_form_html = render_fragment_with_params(
5279                app_root,
5280                "templates/layout/fragments/logout_form.html",
5281                serde_json::Map::from_iter([(
5282                    "logout_button_ui_html".to_owned(),
5283                    Value::String(logout_button_ui_html),
5284                )]),
5285            )?;
5286            nav_home_path = "/".to_owned();
5287            nav_primary = format!("{home_link_html} {file_link_html}");
5288            nav_account = format!("{settings_link_html}{logout_form_html}");
5289            let browser_title = layout_browser_title(app_root, title);
5290            return serde_json::to_string(&serde_json::json!({
5291                "current_lang": resolved_lang,
5292                "current_request_target": current_request_target.unwrap_or("/"),
5293                "title": browser_title,
5294                "nav_home_path": nav_home_path,
5295                "nav_primary": nav_primary,
5296                "nav_account": nav_account,
5297                "body": body,
5298            }))
5299            .ok();
5300        }
5301        let appointments_link_html = render_fragment_with_params(
5302            app_root,
5303            "templates/layout/fragments/nav_link.html",
5304            serde_json::Map::from_iter([
5305                (
5306                    "link_path".to_owned(),
5307                    Value::String("/appointments/".to_owned()),
5308                ),
5309                (
5310                    "link_label".to_owned(),
5311                    Value::String("Appointments".to_owned()),
5312                ),
5313            ]),
5314        )?;
5315        let profile_link_html = render_fragment_with_params(
5316            app_root,
5317            "templates/layout/fragments/nav_link.html",
5318            serde_json::Map::from_iter([
5319                (
5320                    "link_path".to_owned(),
5321                    Value::String("/profile/".to_owned()),
5322                ),
5323                ("link_label".to_owned(), Value::String("Profile".to_owned())),
5324            ]),
5325        )?;
5326        let logout_button_ui_html = render_fragment_with_params(
5327            app_root,
5328            "templates/shared/fragments/ui_button.html",
5329            serde_json::Map::from_iter([
5330                ("id".to_owned(), Value::String("logout_button".to_owned())),
5331                ("button_type".to_owned(), Value::String("submit".to_owned())),
5332                (
5333                    "class_name".to_owned(),
5334                    Value::String("btn btn-secondary".to_owned()),
5335                ),
5336                ("attributes_html".to_owned(), Value::String(String::new())),
5337                (
5338                    "content_html".to_owned(),
5339                    Value::String("Log out".to_owned()),
5340                ),
5341            ]),
5342        )?;
5343        let logout_form_html = render_fragment_with_params(
5344            app_root,
5345            "templates/layout/fragments/logout_form.html",
5346            serde_json::Map::from_iter([(
5347                "logout_button_ui_html".to_owned(),
5348                Value::String(logout_button_ui_html),
5349            )]),
5350        )?;
5351        if matches!(
5352            effective_layout_id,
5353            "public_catalog_shell" | "public_business_shell"
5354        ) {
5355            if effective_layout_id == "public_business_shell" && managed_business_count > 0 {
5356                let manage_business_link_html = render_fragment_with_params(
5357                    app_root,
5358                    "templates/layout/fragments/nav_link.html",
5359                    serde_json::Map::from_iter([
5360                        (
5361                            "link_path".to_owned(),
5362                            Value::String("/businesses/".to_owned()),
5363                        ),
5364                        (
5365                            "link_label".to_owned(),
5366                            Value::String("Manage Businesses".to_owned()),
5367                        ),
5368                    ]),
5369                )?;
5370                nav_primary_value = format!("{appointments_link_html} {manage_business_link_html}");
5371            } else {
5372                nav_primary_value = appointments_link_html;
5373            }
5374            resolved_nav_home_path = "/explore/".to_owned();
5375        } else if matches!(effective_layout_id, "business_shell" | "account_shell")
5376            || managed_business_count > 0
5377        {
5378            let manage_business_link_html = render_fragment_with_params(
5379                app_root,
5380                "templates/layout/fragments/nav_link.html",
5381                serde_json::Map::from_iter([
5382                    (
5383                        "link_path".to_owned(),
5384                        Value::String("/businesses/".to_owned()),
5385                    ),
5386                    (
5387                        "link_label".to_owned(),
5388                        Value::String("Manage Businesses".to_owned()),
5389                    ),
5390                ]),
5391            )?;
5392            nav_primary_value = format!("{appointments_link_html} {manage_business_link_html}");
5393            resolved_nav_home_path = "/explore/".to_owned();
5394        } else {
5395            nav_primary_value = String::new();
5396        }
5397        nav_home_path = resolved_nav_home_path;
5398        nav_primary = nav_primary_value;
5399        nav_account = format!("{language_form_html} {profile_link_html}{logout_form_html}");
5400    } else if effective_layout_id == "architect_shell" {
5401        nav_home_path = "/accounts/login/".to_owned();
5402        nav_primary = String::new();
5403        nav_account = language_form_html;
5404    } else {
5405        nav_home_path = "/accounts/login/".to_owned();
5406        let login_link_html = render_fragment_with_params(
5407            app_root,
5408            "templates/layout/fragments/nav_link.html",
5409            serde_json::Map::from_iter([
5410                (
5411                    "link_path".to_owned(),
5412                    Value::String("/accounts/login/".to_owned()),
5413                ),
5414                ("link_label".to_owned(), Value::String("Log in".to_owned())),
5415            ]),
5416        )?;
5417        let register_link_html = render_fragment_with_params(
5418            app_root,
5419            "templates/layout/fragments/nav_link.html",
5420            serde_json::Map::from_iter([
5421                (
5422                    "link_path".to_owned(),
5423                    Value::String("/accounts/register/".to_owned()),
5424                ),
5425                ("link_label".to_owned(), Value::String("Sign Up".to_owned())),
5426            ]),
5427        )?;
5428        nav_primary = format!("{login_link_html} {register_link_html}");
5429        nav_account = language_form_html;
5430    }
5431
5432    let browser_title = layout_browser_title(app_root, title);
5433    serde_json::to_string(&serde_json::json!({
5434        "current_lang": resolved_lang,
5435        "current_request_target": current_request_target.unwrap_or("/"),
5436        "title": browser_title,
5437        "nav_home_path": nav_home_path,
5438        "nav_primary": nav_primary,
5439        "nav_account": nav_account,
5440        "body": body,
5441    }))
5442    .ok()
5443}
5444
5445pub(crate) fn layout_browser_title(app_root: &Path, title: &str) -> String {
5446    let page_title = title.trim();
5447    let app_name = read_json_or_yaml_file(&app_root.join("pharos.app.json"))
5448        .or_else(|| read_json_or_yaml_file(&app_root.join("pharos.app.yml")))
5449        .or_else(|| read_json_or_yaml_file(&app_root.join("pharos.app.yaml")))
5450        .and_then(|manifest| {
5451            manifest
5452                .get("name")
5453                .and_then(Value::as_str)
5454                .map(str::trim)
5455                .filter(|value| !value.is_empty())
5456                .map(ToOwned::to_owned)
5457        });
5458    let Some(app_name) = app_name else {
5459        return page_title.to_owned();
5460    };
5461    let page_title = page_title
5462        .strip_prefix(&format!("{app_name} — "))
5463        .or_else(|| page_title.strip_prefix(&format!("{app_name} - ")))
5464        .or_else(|| page_title.strip_suffix(&format!(" — {app_name}")))
5465        .or_else(|| page_title.strip_suffix(&format!(" - {app_name}")))
5466        .unwrap_or(page_title)
5467        .trim();
5468    if page_title.is_empty() || page_title == app_name {
5469        app_name
5470    } else {
5471        format!("{app_name} - {page_title}")
5472    }
5473}
5474
5475/// Performs template layout page JSON.
5476///
5477/// # Parameters
5478///
5479/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5480/// - `layout_id`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5481/// - `current_lang`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5482/// - `title`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5483/// - `body`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5484/// - `current_request_target`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5485/// - `has_user`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5486/// - `managed_business_count`: Input consumed by [`crate::runtime::json_commands::template_layout_page_json`].
5487///
5488/// # Returns
5489///
5490/// Returns [`Some`] when [`crate::runtime::json_commands::template_layout_page_json`] can produce a value and [`None`] otherwise.
5491///
5492/// # Examples
5493///
5494/// ```rust,ignore
5495/// let _result = pharos_native::runtime::json_commands::template_layout_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), b"", todo!(), todo!(), todo!());
5496/// ```
5497///
5498/// # Related
5499///
5500/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5501pub fn template_layout_page_json(
5502    app_root: &Path,
5503    layout_id: Option<&str>,
5504    current_lang: Option<&str>,
5505    title: &str,
5506    body: &str,
5507    current_request_target: Option<&str>,
5508    has_user: bool,
5509    managed_business_count: i64,
5510) -> Option<String> {
5511    if app_root.as_os_str().is_empty() || title.is_empty() || body.is_empty() {
5512        return None;
5513    }
5514    build_layout_page_params_json(
5515        app_root,
5516        layout_id,
5517        title,
5518        body,
5519        current_lang,
5520        current_request_target,
5521        has_user,
5522        managed_business_count,
5523    )
5524}
5525
5526/// Performs template layout page HTML.
5527///
5528/// # Parameters
5529///
5530/// - `app_root`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5531/// - `base_path`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5532/// - `layout_id`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5533/// - `current_lang`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5534/// - `title`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5535/// - `body`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5536/// - `current_request_target`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5537/// - `has_user`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5538/// - `managed_business_count`: Input consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5539///
5540/// # Returns
5541///
5542/// Returns [`Some`] when [`crate::runtime::json_commands::template_layout_page_html`] can produce a value and [`None`] otherwise.
5543///
5544/// # Performance
5545///
5546/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::template_layout_page_html`].
5547///
5548/// # Examples
5549///
5550/// ```rust,ignore
5551/// let _result = pharos_native::runtime::json_commands::template_layout_page_html(std::path::Path::new("apps/dev_docs"), "/app", todo!(), todo!(), todo!(), b"", todo!(), todo!(), todo!());
5552/// ```
5553///
5554/// # Related
5555///
5556/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5557pub fn template_layout_page_html(
5558    app_root: &Path,
5559    base_path: Option<&str>,
5560    layout_id: Option<&str>,
5561    current_lang: Option<&str>,
5562    title: &str,
5563    body: &str,
5564    current_request_target: Option<&str>,
5565    has_user: bool,
5566    managed_business_count: i64,
5567) -> Option<String> {
5568    let render_params_json = build_layout_page_params_json(
5569        app_root,
5570        layout_id,
5571        title,
5572        body,
5573        current_lang,
5574        current_request_target,
5575        has_user,
5576        managed_business_count,
5577    )?;
5578    let render_params_root = serde_json::from_str::<Value>(&render_params_json).ok()?;
5579    let rendered = render_file_template(
5580        &app_root.join("templates/layout/base.html"),
5581        &render_params_root,
5582    )?;
5583    template_apply_base_path(&rendered, base_path)
5584}
5585
5586/// Performs validation empty report.
5587///
5588/// # Parameters
5589///
5590/// - `form_id`: Input consumed by [`crate::runtime::json_commands::validation_empty_report`].
5591/// - `action_id`: Input consumed by [`crate::runtime::json_commands::validation_empty_report`].
5592/// - `actor_scope`: Input consumed by [`crate::runtime::json_commands::validation_empty_report`].
5593/// - `tenant_scope`: Input consumed by [`crate::runtime::json_commands::validation_empty_report`].
5594///
5595/// # Returns
5596///
5597/// Returns [`Some`] when [`crate::runtime::json_commands::validation_empty_report`] can produce a value and [`None`] otherwise.
5598///
5599/// # Examples
5600///
5601/// ```rust,ignore
5602/// let _result = pharos_native::runtime::json_commands::validation_empty_report("form", todo!(), todo!(), todo!());
5603/// ```
5604///
5605/// # Related
5606///
5607/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5608pub fn validation_empty_report(
5609    form_id: Option<&str>,
5610    action_id: Option<&str>,
5611    actor_scope: Option<&str>,
5612    tenant_scope: Option<&str>,
5613) -> Option<String> {
5614    serde_json::to_string(&serde_json::json!({
5615        "schema": "pharos.validation.report.v1",
5616        "report_id": "pharos.validation.report.v1",
5617        "form_id": form_id.unwrap_or_default(),
5618        "action_id": action_id.unwrap_or_default(),
5619        "field_errors": [],
5620        "form_errors": [],
5621        "actor_scope": actor_scope.unwrap_or("anonymous"),
5622        "tenant_scope": tenant_scope.unwrap_or("global"),
5623    }))
5624    .ok()
5625}
5626
5627/// Appends validation error.
5628fn append_validation_error(
5629    report_json: &str,
5630    array_name: &str,
5631    field_id: Option<&str>,
5632    rule_id: Option<&str>,
5633    code_text: Option<&str>,
5634    message: Option<&str>,
5635) -> Option<String> {
5636    let mut root = serde_json::from_str::<Value>(report_json).ok()?;
5637    let object = root.as_object_mut()?;
5638    if !matches!(object.get(array_name), Some(Value::Array(_))) {
5639        object.insert(array_name.to_owned(), Value::Array(Vec::new()));
5640    }
5641    let errors = object.get_mut(array_name)?.as_array_mut()?;
5642    let mut entry = serde_json::Map::new();
5643    if let Some(field_id) = field_id.filter(|value| !value.is_empty()) {
5644        entry.insert("field_id".to_owned(), Value::String(field_id.to_owned()));
5645    }
5646    entry.insert(
5647        "rule_id".to_owned(),
5648        Value::String(rule_id.unwrap_or_default().to_owned()),
5649    );
5650    entry.insert(
5651        "code".to_owned(),
5652        Value::String(code_text.unwrap_or_default().to_owned()),
5653    );
5654    entry.insert(
5655        "message".to_owned(),
5656        Value::String(message.unwrap_or_default().to_owned()),
5657    );
5658    errors.push(Value::Object(entry));
5659    serde_json::to_string(&root).ok()
5660}
5661
5662/// Performs validation add field error.
5663///
5664/// # Parameters
5665///
5666/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_add_field_error`].
5667/// - `field_id`: Input consumed by [`crate::runtime::json_commands::validation_add_field_error`].
5668/// - `rule_id`: Input consumed by [`crate::runtime::json_commands::validation_add_field_error`].
5669/// - `code_text`: Input consumed by [`crate::runtime::json_commands::validation_add_field_error`].
5670/// - `message`: Input consumed by [`crate::runtime::json_commands::validation_add_field_error`].
5671///
5672/// # Returns
5673///
5674/// Returns [`Some`] when [`crate::runtime::json_commands::validation_add_field_error`] can produce a value and [`None`] otherwise.
5675///
5676/// # Examples
5677///
5678/// ```rust,ignore
5679/// let _result = pharos_native::runtime::json_commands::validation_add_field_error("{}", "field", todo!(), todo!(), "example");
5680/// ```
5681///
5682/// # Related
5683///
5684/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5685pub fn validation_add_field_error(
5686    report_json: &str,
5687    field_id: Option<&str>,
5688    rule_id: Option<&str>,
5689    code_text: Option<&str>,
5690    message: Option<&str>,
5691) -> Option<String> {
5692    append_validation_error(
5693        report_json,
5694        "field_errors",
5695        field_id,
5696        rule_id,
5697        code_text,
5698        message,
5699    )
5700}
5701
5702/// Performs validation add form error.
5703///
5704/// # Parameters
5705///
5706/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_add_form_error`].
5707/// - `rule_id`: Input consumed by [`crate::runtime::json_commands::validation_add_form_error`].
5708/// - `code_text`: Input consumed by [`crate::runtime::json_commands::validation_add_form_error`].
5709/// - `message`: Input consumed by [`crate::runtime::json_commands::validation_add_form_error`].
5710///
5711/// # Returns
5712///
5713/// Returns [`Some`] when [`crate::runtime::json_commands::validation_add_form_error`] can produce a value and [`None`] otherwise.
5714///
5715/// # Examples
5716///
5717/// ```rust,ignore
5718/// let _result = pharos_native::runtime::json_commands::validation_add_form_error("{}", todo!(), todo!(), "example");
5719/// ```
5720///
5721/// # Related
5722///
5723/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5724pub fn validation_add_form_error(
5725    report_json: &str,
5726    rule_id: Option<&str>,
5727    code_text: Option<&str>,
5728    message: Option<&str>,
5729) -> Option<String> {
5730    append_validation_error(
5731        report_json,
5732        "form_errors",
5733        None,
5734        rule_id,
5735        code_text,
5736        message,
5737    )
5738}
5739
5740/// Performs validation has errors.
5741///
5742/// # Parameters
5743///
5744/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_has_errors`].
5745///
5746/// # Returns
5747///
5748/// Returns [`Some`] when [`crate::runtime::json_commands::validation_has_errors`] can produce a value and [`None`] otherwise.
5749///
5750/// # Performance
5751///
5752/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::validation_has_errors`].
5753///
5754/// # Examples
5755///
5756/// ```rust,ignore
5757/// let _result = pharos_native::runtime::json_commands::validation_has_errors("{}");
5758/// ```
5759///
5760/// # Related
5761///
5762/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5763pub fn validation_has_errors(report_json: &str) -> Option<bool> {
5764    let Some(root) = serde_json::from_str::<Value>(report_json).ok() else {
5765        return Some(false);
5766    };
5767    let field_count = root
5768        .get("field_errors")
5769        .and_then(Value::as_array)
5770        .map(Vec::len)
5771        .unwrap_or(0);
5772    let form_count = root
5773        .get("form_errors")
5774        .and_then(Value::as_array)
5775        .map(Vec::len)
5776        .unwrap_or(0);
5777    Some(field_count + form_count > 0)
5778}
5779
5780/// Performs validation summary text.
5781///
5782/// # Parameters
5783///
5784/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_summary_text`].
5785///
5786/// # Returns
5787///
5788/// Returns [`Some`] when [`crate::runtime::json_commands::validation_summary_text`] can produce a value and [`None`] otherwise.
5789///
5790/// # Performance
5791///
5792/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::validation_summary_text`].
5793///
5794/// # Examples
5795///
5796/// ```rust,ignore
5797/// let _result = pharos_native::runtime::json_commands::validation_summary_text("{}");
5798/// ```
5799///
5800/// # Related
5801///
5802/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5803pub fn validation_summary_text(report_json: &str) -> Option<String> {
5804    let root = serde_json::from_str::<Value>(report_json).ok()?;
5805    let object = root.as_object()?;
5806    let mut items = Vec::new();
5807    for array_name in ["field_errors", "form_errors"] {
5808        if let Some(errors) = object.get(array_name).and_then(Value::as_array) {
5809            for item in errors {
5810                let rule_id = item
5811                    .get("rule_id")
5812                    .and_then(Value::as_str)
5813                    .unwrap_or_default();
5814                let message = item
5815                    .get("message")
5816                    .and_then(Value::as_str)
5817                    .unwrap_or_default();
5818                if !message.is_empty() {
5819                    items.push(format!("[{rule_id}] {message}"));
5820                }
5821            }
5822        }
5823    }
5824    Some(items.join(" "))
5825}
5826
5827/// Performs validation field list HTML.
5828///
5829/// # Parameters
5830///
5831/// - `app_root`: Input consumed by [`crate::runtime::json_commands::validation_field_list_html`].
5832/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_field_list_html`].
5833///
5834/// # Returns
5835///
5836/// Returns [`Some`] when [`crate::runtime::json_commands::validation_field_list_html`] can produce a value and [`None`] otherwise.
5837///
5838/// # Performance
5839///
5840/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::validation_field_list_html`].
5841///
5842/// # Examples
5843///
5844/// ```rust,ignore
5845/// let _result = pharos_native::runtime::json_commands::validation_field_list_html(std::path::Path::new("apps/dev_docs"), "{}");
5846/// ```
5847///
5848/// # Related
5849///
5850/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5851pub fn validation_field_list_html(app_root: &Path, report_json: &str) -> Option<String> {
5852    if app_root.as_os_str().is_empty() {
5853        return None;
5854    }
5855    let root = serde_json::from_str::<Value>(report_json).ok()?;
5856    let object = root.as_object()?;
5857    let mut out = String::new();
5858    if let Some(errors) = object.get("field_errors").and_then(Value::as_array) {
5859        for item in errors {
5860            let rule_id = item
5861                .get("rule_id")
5862                .and_then(Value::as_str)
5863                .unwrap_or_default();
5864            let field_id = item
5865                .get("field_id")
5866                .and_then(Value::as_str)
5867                .unwrap_or_default();
5868            let message = item
5869                .get("message")
5870                .and_then(Value::as_str)
5871                .unwrap_or_default();
5872            out.push_str(&render_fragment_with_params(
5873                app_root,
5874                "templates/shared/fragments/validation_field_error_item.html",
5875                serde_json::Map::from_iter([
5876                    ("rule_id".to_owned(), Value::String(rule_id.to_owned())),
5877                    ("field_id".to_owned(), Value::String(field_id.to_owned())),
5878                    ("message".to_owned(), Value::String(message.to_owned())),
5879                ]),
5880            )?);
5881        }
5882    }
5883    if let Some(errors) = object.get("form_errors").and_then(Value::as_array) {
5884        for item in errors {
5885            let rule_id = item
5886                .get("rule_id")
5887                .and_then(Value::as_str)
5888                .unwrap_or_default();
5889            let message = item
5890                .get("message")
5891                .and_then(Value::as_str)
5892                .unwrap_or_default();
5893            out.push_str(&render_fragment_with_params(
5894                app_root,
5895                "templates/shared/fragments/validation_form_error_item.html",
5896                serde_json::Map::from_iter([
5897                    ("rule_id".to_owned(), Value::String(rule_id.to_owned())),
5898                    ("message".to_owned(), Value::String(message.to_owned())),
5899                ]),
5900            )?);
5901        }
5902    }
5903    Some(out)
5904}
5905
5906/// Trims ascii whitespace range.
5907///
5908/// # Parameters
5909///
5910/// - `text`: Input consumed by [`crate::runtime::json_commands::trim_ascii_whitespace_range`].
5911///
5912/// # Returns
5913///
5914/// Returns the computed value produced by [`crate::runtime::json_commands::trim_ascii_whitespace_range`].
5915///
5916/// # Examples
5917///
5918/// ```rust,ignore
5919/// let _result = pharos_native::runtime::json_commands::trim_ascii_whitespace_range("{}");
5920/// ```
5921///
5922/// # Related
5923///
5924/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5925pub fn trim_ascii_whitespace_range(text: &str) -> (usize, usize) {
5926    let bytes = text.as_bytes();
5927    let mut start = 0usize;
5928    let mut end = bytes.len();
5929    while start < end && bytes[start].is_ascii_whitespace() {
5930        start += 1;
5931    }
5932    while end > start && bytes[end - 1].is_ascii_whitespace() {
5933        end -= 1;
5934    }
5935    (start, end)
5936}
5937
5938/// Performs JSON string array lines.
5939///
5940/// # Parameters
5941///
5942/// - `text`: Input consumed by [`crate::runtime::json_commands::json_string_array_lines`].
5943///
5944/// # Returns
5945///
5946/// Returns [`Some`] when [`crate::runtime::json_commands::json_string_array_lines`] can produce a value and [`None`] otherwise.
5947///
5948/// # Performance
5949///
5950/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_string_array_lines`].
5951///
5952/// # Examples
5953///
5954/// ```rust,ignore
5955/// let _result = pharos_native::runtime::json_commands::json_string_array_lines("{}");
5956/// ```
5957///
5958/// # Related
5959///
5960/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5961pub fn json_string_array_lines(text: &str) -> Option<Vec<String>> {
5962    serde_json::from_str::<Value>(text)
5963        .ok()?
5964        .as_array()?
5965        .iter()
5966        .map(|value| value.as_str().map(ToOwned::to_owned))
5967        .collect()
5968}
5969
5970/// Renders empty card list item.
5971///
5972/// # Parameters
5973///
5974/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_empty_card_list_item`].
5975/// - `message`: Input consumed by [`crate::runtime::json_commands::render_empty_card_list_item`].
5976///
5977/// # Returns
5978///
5979/// Returns [`Some`] when [`crate::runtime::json_commands::render_empty_card_list_item`] can produce a value and [`None`] otherwise.
5980///
5981/// # Examples
5982///
5983/// ```rust,ignore
5984/// let _result = pharos_native::runtime::json_commands::render_empty_card_list_item(std::path::Path::new("apps/dev_docs"), "example");
5985/// ```
5986///
5987/// # Related
5988///
5989/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
5990pub fn render_empty_card_list_item(app_root: &str, message: &str) -> Option<String> {
5991    super::business::render_empty_card_list_item_business_logic_local(app_root, message)
5992}
5993
5994/// Performs surface find by ID.
5995///
5996/// # Parameters
5997///
5998/// - `root`: Input consumed by [`crate::runtime::json_commands::surface_find_by_id`].
5999/// - `surface_id`: Input consumed by [`crate::runtime::json_commands::surface_find_by_id`].
6000///
6001/// # Returns
6002///
6003/// Returns [`Some`] when [`crate::runtime::json_commands::surface_find_by_id`] can produce a value and [`None`] otherwise.
6004///
6005/// # Performance
6006///
6007/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::surface_find_by_id`].
6008///
6009/// # Examples
6010///
6011/// ```rust,ignore
6012/// let _result = pharos_native::runtime::json_commands::surface_find_by_id(std::path::Path::new("."), "surface");
6013/// ```
6014///
6015/// # Related
6016///
6017/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6018pub fn surface_find_by_id(root: &Value, surface_id: &str) -> Option<String> {
6019    root.get("surfaces")?
6020        .as_array()?
6021        .iter()
6022        .find(|surface| {
6023            surface.get("id").and_then(Value::as_str) == Some(surface_id)
6024                || surface.get("surface_id").and_then(Value::as_str) == Some(surface_id)
6025        })
6026        .and_then(compact)
6027}
6028
6029/// Performs error envelope.
6030///
6031/// # Parameters
6032///
6033/// - `error_type`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6034/// - `error_code`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6035/// - `message`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6036/// - `actor_scope`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6037/// - `tenant_scope`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6038/// - `details_json`: Input consumed by [`crate::runtime::json_commands::error_envelope`].
6039///
6040/// # Returns
6041///
6042/// Returns [`Some`] when [`crate::runtime::json_commands::error_envelope`] can produce a value and [`None`] otherwise.
6043///
6044/// # Performance
6045///
6046/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::error_envelope`].
6047///
6048/// # Examples
6049///
6050/// ```rust,ignore
6051/// let _result = pharos_native::runtime::json_commands::error_envelope(todo!(), todo!(), "example", todo!(), todo!(), todo!());
6052/// ```
6053///
6054/// # Related
6055///
6056/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6057pub fn error_envelope(
6058    error_type: Option<&str>,
6059    error_code: Option<&str>,
6060    message: Option<&str>,
6061    actor_scope: Option<&str>,
6062    tenant_scope: Option<&str>,
6063    details_json: Option<&str>,
6064) -> Option<String> {
6065    let details = details_json
6066        .filter(|value| !value.is_empty())
6067        .and_then(|value| serde_json::from_str::<Value>(value).ok());
6068    let mut envelope = pharos_runtime_core::error::envelope(
6069        pharos_runtime_core::error::ErrorCode::InvalidInput,
6070        message.unwrap_or_default(),
6071        None,
6072    );
6073    let error = envelope.get_mut("error")?.as_object_mut()?;
6074    error.insert(
6075        "context".to_owned(),
6076        Value::String(error_type.unwrap_or_default().to_owned()),
6077    );
6078    error.insert(
6079        "declared_code".to_owned(),
6080        Value::String(error_code.unwrap_or_default().to_owned()),
6081    );
6082    error.insert(
6083        "actor_scope".to_owned(),
6084        Value::String(actor_scope.unwrap_or("anonymous").to_owned()),
6085    );
6086    error.insert(
6087        "tenant_scope".to_owned(),
6088        Value::String(tenant_scope.unwrap_or("global").to_owned()),
6089    );
6090    error.insert("details".to_owned(), details.unwrap_or(Value::Null));
6091    serde_json::to_string(&envelope).ok()
6092}
6093
6094/// Performs validation error envelope.
6095///
6096/// # Parameters
6097///
6098/// - `report_json`: Input consumed by [`crate::runtime::json_commands::validation_error_envelope`].
6099///
6100/// # Returns
6101///
6102/// Returns [`Some`] when [`crate::runtime::json_commands::validation_error_envelope`] can produce a value and [`None`] otherwise.
6103///
6104/// # Performance
6105///
6106/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::validation_error_envelope`].
6107///
6108/// # Examples
6109///
6110/// ```rust,ignore
6111/// let _result = pharos_native::runtime::json_commands::validation_error_envelope("{}");
6112/// ```
6113///
6114/// # Related
6115///
6116/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6117pub fn validation_error_envelope(report_json: &str) -> Option<String> {
6118    let root = serde_json::from_str::<Value>(report_json).ok()?;
6119    let actor_scope = root
6120        .get("actor_scope")
6121        .and_then(Value::as_str)
6122        .unwrap_or("anonymous");
6123    let tenant_scope = root
6124        .get("tenant_scope")
6125        .and_then(Value::as_str)
6126        .unwrap_or("global");
6127    let mut envelope = pharos_runtime_core::error::envelope(
6128        pharos_runtime_core::error::ErrorCode::InvalidInput,
6129        "Validation failed.",
6130        None,
6131    );
6132    let error = envelope.get_mut("error")?.as_object_mut()?;
6133    error.insert(
6134        "context".to_owned(),
6135        Value::String("validation_error".to_owned()),
6136    );
6137    error.insert(
6138        "declared_code".to_owned(),
6139        Value::String("validation_failed".to_owned()),
6140    );
6141    error.insert(
6142        "actor_scope".to_owned(),
6143        Value::String(actor_scope.to_owned()),
6144    );
6145    error.insert(
6146        "tenant_scope".to_owned(),
6147        Value::String(tenant_scope.to_owned()),
6148    );
6149    error.insert("details".to_owned(), root);
6150    serde_json::to_string(&envelope).ok()
6151}
6152
6153/// Handles validation empty report command.
6154///
6155/// # Parameters
6156///
6157/// - `form_id`: Input consumed by [`crate::runtime::json_commands::handle_validation_empty_report_command`].
6158/// - `action_id`: Input consumed by [`crate::runtime::json_commands::handle_validation_empty_report_command`].
6159/// - `actor_scope`: Input consumed by [`crate::runtime::json_commands::handle_validation_empty_report_command`].
6160/// - `tenant_scope`: Input consumed by [`crate::runtime::json_commands::handle_validation_empty_report_command`].
6161///
6162/// # Returns
6163///
6164/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_empty_report_command`] can produce a value and [`None`] otherwise.
6165///
6166/// # Examples
6167///
6168/// ```rust,ignore
6169/// let _result = pharos_native::runtime::json_commands::handle_validation_empty_report_command("form", todo!(), todo!(), todo!());
6170/// ```
6171///
6172/// # Related
6173///
6174/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6175pub fn handle_validation_empty_report_command(
6176    form_id: Option<&str>,
6177    action_id: Option<&str>,
6178    actor_scope: Option<&str>,
6179    tenant_scope: Option<&str>,
6180) -> Option<String> {
6181    validation_empty_report(form_id, action_id, actor_scope, tenant_scope)
6182}
6183
6184/// Handles validation add field error command.
6185///
6186/// # Parameters
6187///
6188/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_field_error_command`].
6189/// - `field_id`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_field_error_command`].
6190/// - `rule_id`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_field_error_command`].
6191/// - `code_text`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_field_error_command`].
6192/// - `message`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_field_error_command`].
6193///
6194/// # Returns
6195///
6196/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_add_field_error_command`] can produce a value and [`None`] otherwise.
6197///
6198/// # Examples
6199///
6200/// ```rust,ignore
6201/// let _result = pharos_native::runtime::json_commands::handle_validation_add_field_error_command("{}", "field", todo!(), todo!(), "example");
6202/// ```
6203///
6204/// # Related
6205///
6206/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6207pub fn handle_validation_add_field_error_command(
6208    report_json: &str,
6209    field_id: Option<&str>,
6210    rule_id: Option<&str>,
6211    code_text: Option<&str>,
6212    message: Option<&str>,
6213) -> Option<String> {
6214    validation_add_field_error(report_json, field_id, rule_id, code_text, message)
6215}
6216
6217/// Handles validation add form error command.
6218///
6219/// # Parameters
6220///
6221/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_form_error_command`].
6222/// - `rule_id`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_form_error_command`].
6223/// - `code_text`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_form_error_command`].
6224/// - `message`: Input consumed by [`crate::runtime::json_commands::handle_validation_add_form_error_command`].
6225///
6226/// # Returns
6227///
6228/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_add_form_error_command`] can produce a value and [`None`] otherwise.
6229///
6230/// # Examples
6231///
6232/// ```rust,ignore
6233/// let _result = pharos_native::runtime::json_commands::handle_validation_add_form_error_command("{}", todo!(), todo!(), "example");
6234/// ```
6235///
6236/// # Related
6237///
6238/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6239pub fn handle_validation_add_form_error_command(
6240    report_json: &str,
6241    rule_id: Option<&str>,
6242    code_text: Option<&str>,
6243    message: Option<&str>,
6244) -> Option<String> {
6245    validation_add_form_error(report_json, rule_id, code_text, message)
6246}
6247
6248/// Handles validation has errors command.
6249///
6250/// # Parameters
6251///
6252/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_has_errors_command`].
6253///
6254/// # Returns
6255///
6256/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_has_errors_command`] can produce a value and [`None`] otherwise.
6257///
6258/// # Examples
6259///
6260/// ```rust,ignore
6261/// let _result = pharos_native::runtime::json_commands::handle_validation_has_errors_command("{}");
6262/// ```
6263///
6264/// # Related
6265///
6266/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6267pub fn handle_validation_has_errors_command(report_json: &str) -> Option<bool> {
6268    validation_has_errors(report_json)
6269}
6270
6271/// Handles validation summary text command.
6272///
6273/// # Parameters
6274///
6275/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_summary_text_command`].
6276///
6277/// # Returns
6278///
6279/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_summary_text_command`] can produce a value and [`None`] otherwise.
6280///
6281/// # Examples
6282///
6283/// ```rust,ignore
6284/// let _result = pharos_native::runtime::json_commands::handle_validation_summary_text_command("{}");
6285/// ```
6286///
6287/// # Related
6288///
6289/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6290pub fn handle_validation_summary_text_command(report_json: &str) -> Option<String> {
6291    validation_summary_text(report_json)
6292}
6293
6294/// Handles validation field list HTML command.
6295///
6296/// # Parameters
6297///
6298/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_validation_field_list_html_command`].
6299/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_field_list_html_command`].
6300///
6301/// # Returns
6302///
6303/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_field_list_html_command`] can produce a value and [`None`] otherwise.
6304///
6305/// # Examples
6306///
6307/// ```rust,ignore
6308/// let _result = pharos_native::runtime::json_commands::handle_validation_field_list_html_command(std::path::Path::new("apps/dev_docs"), "{}");
6309/// ```
6310///
6311/// # Related
6312///
6313/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6314pub fn handle_validation_field_list_html_command(
6315    app_root: &Path,
6316    report_json: &str,
6317) -> Option<String> {
6318    validation_field_list_html(app_root, report_json)
6319}
6320
6321/// Handles error envelope command.
6322///
6323/// # Parameters
6324///
6325/// - `error_type`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6326/// - `error_code`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6327/// - `message`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6328/// - `actor_scope`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6329/// - `tenant_scope`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6330/// - `details_json`: Input consumed by [`crate::runtime::json_commands::handle_error_envelope_command`].
6331///
6332/// # Returns
6333///
6334/// Returns [`Some`] when [`crate::runtime::json_commands::handle_error_envelope_command`] can produce a value and [`None`] otherwise.
6335///
6336/// # Examples
6337///
6338/// ```rust,ignore
6339/// let _result = pharos_native::runtime::json_commands::handle_error_envelope_command(todo!(), todo!(), "example", todo!(), todo!(), todo!());
6340/// ```
6341///
6342/// # Related
6343///
6344/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6345pub fn handle_error_envelope_command(
6346    error_type: Option<&str>,
6347    error_code: Option<&str>,
6348    message: Option<&str>,
6349    actor_scope: Option<&str>,
6350    tenant_scope: Option<&str>,
6351    details_json: Option<&str>,
6352) -> Option<String> {
6353    error_envelope(
6354        error_type,
6355        error_code,
6356        message,
6357        actor_scope,
6358        tenant_scope,
6359        details_json,
6360    )
6361}
6362
6363/// Handles validation error envelope command.
6364///
6365/// # Parameters
6366///
6367/// - `report_json`: Input consumed by [`crate::runtime::json_commands::handle_validation_error_envelope_command`].
6368///
6369/// # Returns
6370///
6371/// Returns [`Some`] when [`crate::runtime::json_commands::handle_validation_error_envelope_command`] can produce a value and [`None`] otherwise.
6372///
6373/// # Examples
6374///
6375/// ```rust,ignore
6376/// let _result = pharos_native::runtime::json_commands::handle_validation_error_envelope_command("{}");
6377/// ```
6378///
6379/// # Related
6380///
6381/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6382pub fn handle_validation_error_envelope_command(report_json: &str) -> Option<String> {
6383    validation_error_envelope(report_json)
6384}
6385
6386/// Performs route template params.
6387fn route_template_params(
6388    template_path: &str,
6389    request_path: &str,
6390) -> Option<serde_json::Map<String, Value>> {
6391    if template_path.is_empty() || request_path.is_empty() {
6392        return None;
6393    }
6394    let template_segments: Vec<&str> = template_path.trim_matches('/').split('/').collect();
6395    let request_segments: Vec<&str> = request_path
6396        .split('?')
6397        .next()
6398        .unwrap_or_default()
6399        .trim_matches('/')
6400        .split('/')
6401        .collect();
6402    if template_segments.len() != request_segments.len() {
6403        return None;
6404    }
6405    let mut params = serde_json::Map::new();
6406    for (template, actual) in template_segments.iter().zip(request_segments.iter()) {
6407        if let Some(name) = template
6408            .strip_prefix('{')
6409            .and_then(|value| value.strip_suffix('}'))
6410        {
6411            if name.is_empty() || actual.is_empty() {
6412                return None;
6413            }
6414            params.insert(name.to_owned(), Value::String((*actual).to_owned()));
6415        } else if template != actual {
6416            return None;
6417        }
6418    }
6419    Some(params)
6420}
6421
6422/// Matches one request against generated API/admin operation declarations in a contract file.
6423///
6424/// # Parameters
6425///
6426/// - `file_path`: Input consumed by [`crate::runtime::json_commands::file_generated_surface_match`].
6427/// - `method`: Input consumed by [`crate::runtime::json_commands::file_generated_surface_match`].
6428/// - `request_path`: Input consumed by [`crate::runtime::json_commands::file_generated_surface_match`].
6429///
6430/// # Returns
6431///
6432/// Returns [`Some`] when [`crate::runtime::json_commands::file_generated_surface_match`] can produce a value and [`None`] otherwise.
6433///
6434/// # Performance
6435///
6436/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::file_generated_surface_match`].
6437///
6438/// # Examples
6439///
6440/// ```rust,ignore
6441/// let _result = pharos_native::runtime::json_commands::file_generated_surface_match(todo!(), todo!(), "/");
6442/// ```
6443///
6444/// # Related
6445///
6446/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6447pub fn file_generated_surface_match(
6448    file_path: &Path,
6449    method: &str,
6450    request_path: &str,
6451) -> Option<String> {
6452    if file_path.as_os_str().is_empty() || method.is_empty() || request_path.is_empty() {
6453        return None;
6454    }
6455    let root = read_json_file(file_path)?;
6456    for surface in root.get("surfaces").and_then(Value::as_array)? {
6457        if !matches!(
6458            surface.get("surface_kind").and_then(Value::as_str),
6459            Some("generated_api") | Some("generated_admin")
6460        ) {
6461            continue;
6462        }
6463        let Some(operations) = surface.get("operations").and_then(Value::as_object) else {
6464            continue;
6465        };
6466        for (operation_name, operation_config) in operations {
6467            let operation_method = operation_config
6468                .get("method")
6469                .and_then(Value::as_str)
6470                .unwrap_or("GET");
6471            let operation_path = operation_config.get("path").and_then(Value::as_str)?;
6472            if operation_method != method {
6473                continue;
6474            }
6475            let Some(params) = route_template_params(operation_path, request_path) else {
6476                continue;
6477            };
6478            return serde_json::to_string(&serde_json::json!({
6479                "surface": surface,
6480                "operation": operation_name,
6481                "operation_config": operation_config,
6482                "params": Value::Object(params),
6483            }))
6484            .ok();
6485        }
6486    }
6487    None
6488}
6489
6490/// Performs generated surface label.
6491fn generated_surface_label(field_name: &str) -> String {
6492    field_name
6493        .split('_')
6494        .filter(|part| !part.is_empty())
6495        .map(|part| {
6496            let mut chars = part.chars();
6497            match chars.next() {
6498                Some(first) => format!("{}{}", first.to_ascii_uppercase(), chars.as_str()),
6499                None => String::new(),
6500            }
6501        })
6502        .collect::<Vec<_>>()
6503        .join(" ")
6504}
6505
6506/// Returns generated-admin list-column metadata, applying the native fallback contract.
6507///
6508/// # Parameters
6509///
6510/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_columns`].
6511///
6512/// # Returns
6513///
6514/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_list_columns`] can produce a value and [`None`] otherwise.
6515///
6516/// # Performance
6517///
6518/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_list_columns`].
6519///
6520/// # Examples
6521///
6522/// ```rust,ignore
6523/// let _result = pharos_native::runtime::json_commands::generated_surface_list_columns("{}");
6524/// ```
6525///
6526/// # Related
6527///
6528/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6529pub fn generated_surface_list_columns(surface_json: &str) -> Option<String> {
6530    let root = serde_json::from_str::<Value>(surface_json).ok()?;
6531    if let Some(columns) = root
6532        .get("admin")
6533        .and_then(|value| value.get("list_columns"))
6534        .filter(|value| value.is_array())
6535    {
6536        return serde_json::to_string(columns).ok();
6537    }
6538    let mut columns = Vec::new();
6539    for field in root.get("response_fields").and_then(Value::as_array)? {
6540        let Some(field_name) = field.as_str() else {
6541            continue;
6542        };
6543        if matches!(field_name, "id" | "business_id") || columns.len() >= 4 {
6544            continue;
6545        }
6546        columns.push(serde_json::json!({
6547            "field": field_name,
6548            "label": generated_surface_label(field_name),
6549        }));
6550    }
6551    serde_json::to_string(&Value::Array(columns)).ok()
6552}
6553
6554/// Builds the context and identity parameter object used by generated routes.
6555///
6556/// # Parameters
6557///
6558/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_params`].
6559/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_params`].
6560/// - `identity_value`: Input consumed by [`crate::runtime::json_commands::generated_surface_params`].
6561///
6562/// # Returns
6563///
6564/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_params`] can produce a value and [`None`] otherwise.
6565///
6566/// # Performance
6567///
6568/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_params`].
6569///
6570/// # Examples
6571///
6572/// ```rust,ignore
6573/// let _result = pharos_native::runtime::json_commands::generated_surface_params("{}", todo!(), todo!());
6574/// ```
6575///
6576/// # Related
6577///
6578/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6579pub fn generated_surface_params(
6580    surface_json: &str,
6581    context_json: &str,
6582    identity_value: Option<&str>,
6583) -> Option<String> {
6584    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
6585    let context = serde_json::from_str::<Value>(context_json).ok()?;
6586    let mut params = serde_json::Map::new();
6587    if let Some(param) = surface
6588        .get("context_binding")
6589        .and_then(|value| value.get("param"))
6590        .and_then(Value::as_str)
6591        .filter(|value| !value.is_empty())
6592        && let Some(value) = context.get("context_value")
6593        && !value.is_null()
6594    {
6595        params.insert(param.to_owned(), value.clone());
6596    }
6597    if let Some(param) = surface
6598        .get("identity_param")
6599        .and_then(Value::as_str)
6600        .filter(|value| !value.is_empty())
6601        && let Some(identity_value) = identity_value.filter(|value| !value.is_empty())
6602    {
6603        params.insert(param.to_owned(), Value::String(identity_value.to_owned()));
6604    }
6605    serde_json::to_string(&Value::Object(params)).ok()
6606}
6607
6608/// Converts one generated-surface field value to the native display-text contract.
6609///
6610/// # Parameters
6611///
6612/// - `item_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_display_value`].
6613/// - `field_name`: Input consumed by [`crate::runtime::json_commands::generated_surface_display_value`].
6614///
6615/// # Returns
6616///
6617/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_display_value`] can produce a value and [`None`] otherwise.
6618///
6619/// # Performance
6620///
6621/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_display_value`].
6622///
6623/// # Examples
6624///
6625/// ```rust,ignore
6626/// let _result = pharos_native::runtime::json_commands::generated_surface_display_value("{}", todo!());
6627/// ```
6628///
6629/// # Related
6630///
6631/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6632pub fn generated_surface_display_value(item_json: &str, field_name: &str) -> Option<String> {
6633    if field_name.is_empty() {
6634        return None;
6635    }
6636    let root = serde_json::from_str::<Value>(item_json).ok()?;
6637    let value = root.get(field_name);
6638    match value {
6639        None | Some(Value::Null) => Some(String::new()),
6640        Some(Value::Array(items)) => Some(
6641            items
6642                .iter()
6643                .map(|item| match item {
6644                    Value::Bool(flag) => {
6645                        if *flag {
6646                            "yes".to_owned()
6647                        } else {
6648                            "no".to_owned()
6649                        }
6650                    }
6651                    _ => value_to_text(item),
6652                })
6653                .collect::<Vec<_>>()
6654                .join(", "),
6655        ),
6656        Some(Value::Bool(flag)) => Some(if *flag { "yes" } else { "no" }.to_owned()),
6657        Some(value) => Some(value_to_text(value)),
6658    }
6659}
6660
6661/// Performs value to text.
6662fn value_to_text(value: &Value) -> String {
6663    match value {
6664        Value::Null => String::new(),
6665        Value::String(text) => text.clone(),
6666        Value::Bool(flag) => flag.to_string(),
6667        Value::Number(number) => number.to_string(),
6668        _ => serde_json::to_string(value).unwrap_or_default(),
6669    }
6670}
6671
6672/// Renders UI element HTML.
6673fn render_ui_element_html(
6674    app_root: &Path,
6675    element_type: &str,
6676    input_type: Option<&str>,
6677    id: &str,
6678    name: &str,
6679    label: &str,
6680    value: &str,
6681    options_html: &str,
6682) -> Option<String> {
6683    let params = super::ui::ui_render_param_map(
6684        id,
6685        input_type,
6686        Some(if element_type == "button" {
6687            "submit"
6688        } else {
6689            "button"
6690        }),
6691        name,
6692        label,
6693        label,
6694        value,
6695        None,
6696        None,
6697        "",
6698        options_html,
6699        "",
6700        value,
6701        element_type,
6702    )?;
6703    let fragment_path = match element_type {
6704        "select" => "templates/shared/fragments/ui_select.html",
6705        "textarea" => "templates/shared/fragments/ui_textarea.html",
6706        "checkbox" => "templates/shared/fragments/ui_checkbox.html",
6707        _ => "templates/shared/fragments/ui_input.html",
6708    };
6709    generated::render_generated_admin_fragment_from_value_runtime(app_root, fragment_path, &params)
6710}
6711
6712/// Renders select options from one generated-surface field declaration.
6713///
6714/// # Parameters
6715///
6716/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_select_options_html`].
6717/// - `field_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_select_options_html`].
6718/// - `selected_value`: Input consumed by [`crate::runtime::json_commands::generated_surface_select_options_html`].
6719///
6720/// # Returns
6721///
6722/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_select_options_html`] can produce a value and [`None`] otherwise.
6723///
6724/// # Performance
6725///
6726/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_select_options_html`].
6727///
6728/// # Examples
6729///
6730/// ```rust,ignore
6731/// let _result = pharos_native::runtime::json_commands::generated_surface_select_options_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
6732/// ```
6733///
6734/// # Related
6735///
6736/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6737pub fn generated_surface_select_options_html(
6738    app_root: &Path,
6739    field_json: &str,
6740    selected_value: Option<&str>,
6741) -> Option<String> {
6742    if app_root.as_os_str().is_empty() {
6743        return None;
6744    }
6745    let field = serde_json::from_str::<Value>(field_json).ok()?;
6746    let mut out = String::new();
6747    let mut selected_found = false;
6748    for option in field.get("options").and_then(Value::as_array)? {
6749        let value = option
6750            .get("value")
6751            .map(value_to_text)
6752            .filter(|value| !value.is_empty())
6753            .or_else(|| option.get("id").map(value_to_text))
6754            .or_else(|| option.get("name").map(value_to_text))?;
6755        let label = option
6756            .get("label")
6757            .map(value_to_text)
6758            .filter(|value| !value.is_empty())
6759            .or_else(|| option.get("name").map(value_to_text))
6760            .unwrap_or_else(|| value.clone());
6761        let selected = selected_value == Some(value.as_str());
6762        selected_found |= selected;
6763        out.push_str(&render_fragment_with_params(
6764            app_root,
6765            "templates/shared/fragments/select_option.html",
6766            serde_json::Map::from_iter([
6767                ("option_value".to_owned(), Value::String(value)),
6768                (
6769                    "selected_attr".to_owned(),
6770                    Value::String(if selected { " selected" } else { "" }.to_owned()),
6771                ),
6772                ("option_label".to_owned(), Value::String(label)),
6773            ]),
6774        )?);
6775    }
6776    if !selected_found && let Some(selected) = selected_value.filter(|value| !value.is_empty()) {
6777        out.push_str(&render_fragment_with_params(
6778            app_root,
6779            "templates/shared/fragments/select_option.html",
6780            serde_json::Map::from_iter([
6781                (
6782                    "option_value".to_owned(),
6783                    Value::String(selected.to_owned()),
6784                ),
6785                (
6786                    "selected_attr".to_owned(),
6787                    Value::String(" selected".to_owned()),
6788                ),
6789                (
6790                    "option_label".to_owned(),
6791                    Value::String(selected.to_owned()),
6792                ),
6793            ]),
6794        )?);
6795    }
6796    Some(out)
6797}
6798
6799/// Renders generated-surface filter controls from a query string and declaration.
6800///
6801/// # Parameters
6802///
6803/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_filter_controls_html`].
6804/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_filter_controls_html`].
6805/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::generated_surface_filter_controls_html`].
6806///
6807/// # Returns
6808///
6809/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_filter_controls_html`] can produce a value and [`None`] otherwise.
6810///
6811/// # Performance
6812///
6813/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_filter_controls_html`].
6814///
6815/// # Examples
6816///
6817/// ```rust,ignore
6818/// let _result = pharos_native::runtime::json_commands::generated_surface_filter_controls_html(std::path::Path::new("apps/dev_docs"), "{}", todo!());
6819/// ```
6820///
6821/// # Related
6822///
6823/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6824pub fn generated_surface_filter_controls_html(
6825    app_root: &Path,
6826    surface_json: &str,
6827    raw_query: &str,
6828) -> Option<String> {
6829    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
6830    let mut out = String::new();
6831    for filter in surface.get("filters").and_then(Value::as_array)? {
6832        let query = filter
6833            .get("query")
6834            .and_then(Value::as_str)
6835            .unwrap_or_default();
6836        let field = filter.get("field").and_then(Value::as_str).unwrap_or(query);
6837        if query.is_empty() {
6838            continue;
6839        }
6840        let label = filter
6841            .get("label")
6842            .and_then(Value::as_str)
6843            .filter(|value| !value.is_empty())
6844            .unwrap_or(if field.is_empty() { query } else { field });
6845        let match_kind = filter
6846            .get("match")
6847            .and_then(Value::as_str)
6848            .filter(|value| !value.is_empty())
6849            .unwrap_or("exact");
6850        let value = request_query_value(raw_query, query)
6851            .filter(|value| !value.is_empty())
6852            .or_else(|| filter.get("default").map(value_to_text))
6853            .unwrap_or_default();
6854        let options = if match_kind == "boolean" {
6855            render_fragment_with_params(
6856                app_root,
6857                "templates/shared/fragments/boolean_filter_options.html",
6858                serde_json::Map::from_iter([
6859                    (
6860                        "selected_true_attr".to_owned(),
6861                        Value::String(
6862                            if value.is_empty() || value == "true" {
6863                                " selected"
6864                            } else {
6865                                ""
6866                            }
6867                            .to_owned(),
6868                        ),
6869                    ),
6870                    (
6871                        "selected_false_attr".to_owned(),
6872                        Value::String(if value == "false" { " selected" } else { "" }.to_owned()),
6873                    ),
6874                    (
6875                        "selected_all_attr".to_owned(),
6876                        Value::String(if value == "all" { " selected" } else { "" }.to_owned()),
6877                    ),
6878                ]),
6879            )?
6880        } else {
6881            let mut html = render_fragment_with_params(
6882                app_root,
6883                "templates/shared/fragments/select_option.html",
6884                serde_json::Map::from_iter([
6885                    ("option_value".to_owned(), Value::String(String::new())),
6886                    (
6887                        "selected_attr".to_owned(),
6888                        Value::String(if value.is_empty() { " selected" } else { "" }.to_owned()),
6889                    ),
6890                    ("option_label".to_owned(), Value::String("All".to_owned())),
6891                ]),
6892            )?;
6893            html.push_str(&generated_surface_select_options_html(
6894                app_root,
6895                &serde_json::to_string(filter).ok()?,
6896                Some(&value),
6897            )?);
6898            html
6899        };
6900        let element = if match_kind == "boolean" || filter.get("options").is_some() {
6901            "select"
6902        } else {
6903            "input"
6904        };
6905        let html = render_ui_element_html(
6906            app_root,
6907            element,
6908            Some(if match_kind == "array_contains_integer" {
6909                "number"
6910            } else {
6911                "text"
6912            }),
6913            query,
6914            query,
6915            label,
6916            &value,
6917            &options,
6918        )?;
6919        out.push_str(&html);
6920    }
6921    Some(out)
6922}
6923
6924/// Renders generated-surface sort options using the native selected-sort rules.
6925///
6926/// # Parameters
6927///
6928/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_sort_options_html`].
6929/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_sort_options_html`].
6930/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::generated_surface_sort_options_html`].
6931///
6932/// # Returns
6933///
6934/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_sort_options_html`] can produce a value and [`None`] otherwise.
6935///
6936/// # Performance
6937///
6938/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_sort_options_html`].
6939///
6940/// # Examples
6941///
6942/// ```rust,ignore
6943/// let _result = pharos_native::runtime::json_commands::generated_surface_sort_options_html(std::path::Path::new("apps/dev_docs"), "{}", todo!());
6944/// ```
6945///
6946/// # Related
6947///
6948/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
6949pub fn generated_surface_sort_options_html(
6950    app_root: &Path,
6951    surface_json: &str,
6952    raw_query: &str,
6953) -> Option<String> {
6954    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
6955    let current = request_query_value(raw_query, "sort")
6956        .filter(|value| !value.is_empty())
6957        .or_else(|| {
6958            surface
6959                .get("default_sort")
6960                .and_then(Value::as_str)
6961                .map(ToOwned::to_owned)
6962        })
6963        .unwrap_or_default();
6964    let mut out = String::new();
6965    for sort in surface.get("sorts").and_then(Value::as_array)? {
6966        let key = sort.get("key").and_then(Value::as_str).unwrap_or_default();
6967        if key.is_empty() {
6968            continue;
6969        }
6970        let label = sort
6971            .get("label")
6972            .and_then(Value::as_str)
6973            .filter(|value| !value.is_empty())
6974            .unwrap_or(key);
6975        out.push_str(&render_fragment_with_params(
6976            app_root,
6977            "templates/shared/fragments/select_option.html",
6978            serde_json::Map::from_iter([
6979                ("option_value".to_owned(), Value::String(key.to_owned())),
6980                (
6981                    "selected_attr".to_owned(),
6982                    Value::String(if current == key { " selected" } else { "" }.to_owned()),
6983                ),
6984                ("option_label".to_owned(), Value::String(label.to_owned())),
6985            ]),
6986        )?);
6987    }
6988    Some(out)
6989}
6990
6991/// Performs state option i64.
6992fn state_option_i64(options: &Value, key: &str, default_value: i64) -> i64 {
6993    options
6994        .get(key)
6995        .and_then(|value| match value {
6996            Value::Number(number) => number.as_i64(),
6997            Value::String(text) => text.parse::<i64>().ok(),
6998            _ => None,
6999        })
7000        .unwrap_or(default_value)
7001}
7002
7003/// Performs state option string.
7004fn state_option_string<'a>(options: &'a Value, key: &str) -> Option<&'a str> {
7005    options
7006        .get(key)
7007        .and_then(Value::as_str)
7008        .filter(|value| !value.is_empty())
7009}
7010
7011/// Performs state rows.
7012fn state_rows<'a>(root: &'a Value, section: &str) -> &'a [Value] {
7013    root.get(section)
7014        .and_then(Value::as_array)
7015        .map(Vec::as_slice)
7016        .unwrap_or(&[])
7017}
7018
7019/// Performs state row by ID.
7020fn state_row_by_id<'a>(root: &'a Value, section: &str, id: i64) -> Option<&'a Value> {
7021    (id > 0).then_some(())?;
7022    state_rows(root, section).iter().find(|row| {
7023        row.get("id").and_then(Value::as_i64) == Some(id)
7024            || row
7025                .get("id")
7026                .and_then(Value::as_str)
7027                .and_then(|value| value.parse::<i64>().ok())
7028                == Some(id)
7029    })
7030}
7031
7032/// Performs state row by text.
7033fn state_row_by_text<'a>(
7034    root: &'a Value,
7035    section: &str,
7036    field: &str,
7037    wanted: &str,
7038) -> Option<&'a Value> {
7039    if field.is_empty() || wanted.is_empty() {
7040        return None;
7041    }
7042    state_rows(root, section)
7043        .iter()
7044        .find(|row| row.get(field).and_then(Value::as_str) == Some(wanted))
7045}
7046
7047/// Performs state JSON or empty.
7048fn state_json_or_empty(value: Option<&Value>) -> String {
7049    value
7050        .and_then(|value| serde_json::to_string(value).ok())
7051        .unwrap_or_else(|| "{}".to_owned())
7052}
7053
7054/// Performs state lines.
7055fn state_lines(rows: &[Value], field: &str) -> String {
7056    rows.iter()
7057        .filter_map(|row| row.get(field))
7058        .map(value_to_text)
7059        .filter(|value| !value.is_empty())
7060        .collect::<Vec<_>>()
7061        .join("\n")
7062}
7063
7064/// Performs state next ID.
7065fn state_next_id(root: &Value, section: &str) -> i64 {
7066    state_rows(root, section)
7067        .iter()
7068        .filter_map(|row| row.get("id"))
7069        .filter_map(|value| {
7070            value
7071                .as_i64()
7072                .or_else(|| value.as_str()?.parse::<i64>().ok())
7073        })
7074        .max()
7075        .unwrap_or(0)
7076        + 1
7077}
7078
7079/// Performs state active token.
7080fn state_active_token<'a>(
7081    root: &'a Value,
7082    section: &str,
7083    token_hash: &str,
7084    now_iso: &str,
7085) -> Option<&'a Value> {
7086    state_rows(root, section).iter().find(|row| {
7087        row.get("token_hash").and_then(Value::as_str) == Some(token_hash)
7088            && row
7089                .get("claimed_at")
7090                .is_none_or(|value| value.is_null() || value.as_str() == Some(""))
7091            && row
7092                .get("expires_at")
7093                .and_then(Value::as_str)
7094                .is_some_and(|expires| expires > now_iso)
7095    })
7096}
7097
7098/// Performs state write.
7099fn state_write(root: &Value, state_path: &Path) -> Result<String, i32> {
7100    if generated::write_json_file(state_path, root) {
7101        Ok(String::new())
7102    } else {
7103        Err(69)
7104    }
7105}
7106
7107/// Executes one state JSON command against the persisted runtime-state contract.
7108///
7109/// # Parameters
7110///
7111/// - `state_path`: Input consumed by [`crate::runtime::json_commands::state_named_command`].
7112/// - `name`: Input consumed by [`crate::runtime::json_commands::state_named_command`].
7113/// - `options_json`: Input consumed by [`crate::runtime::json_commands::state_named_command`].
7114///
7115/// # Returns
7116///
7117/// Returns the successful value produced by [`crate::runtime::json_commands::state_named_command`] or an error when the operation fails.
7118///
7119/// # Errors
7120///
7121/// Returns an error value when [`crate::runtime::json_commands::state_named_command`] cannot complete successfully.
7122///
7123/// # Performance
7124///
7125/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_named_command`].
7126///
7127/// # Examples
7128///
7129/// ```rust,ignore
7130/// let _result = pharos_native::runtime::json_commands::state_named_command(todo!(), "name", todo!());
7131/// ```
7132///
7133/// # Related
7134///
7135/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7136pub fn state_named_command(
7137    state_path: &Path,
7138    name: &str,
7139    options_json: &str,
7140) -> Result<String, i32> {
7141    if state_path.as_os_str().is_empty() || name.is_empty() {
7142        return Err(64);
7143    }
7144    let mut root = read_json_file(state_path).ok_or(66)?;
7145    if !root.is_object() {
7146        return Err(66);
7147    }
7148    let options = if options_json.is_empty() {
7149        serde_json::json!({})
7150    } else {
7151        serde_json::from_str::<Value>(options_json).map_err(|_| 64)?
7152    };
7153    if !options.is_object() {
7154        return Err(64);
7155    }
7156
7157    let id = |key: &str| state_option_i64(&options, key, 0);
7158    let text = |key: &str| state_option_string(&options, key).unwrap_or_default();
7159    let output_json = |value: Option<&Value>| Ok(state_json_or_empty(value));
7160
7161    match name {
7162        "import-row-json-lines" => {
7163            let section = text("section");
7164            let rows = options.get("rows").and_then(Value::as_array).ok_or(64)?.clone();
7165            if section.is_empty() { return Err(64); }
7166            let target = root.as_object_mut().ok_or(66)?.entry(section.to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?;
7167            target.extend(rows.into_iter().filter(Value::is_object));
7168            state_write(&root, state_path)
7169        }
7170        "business-json-by-slug" => output_json(generated::dynamic_find_business_by_slug(&root, text("slug"))),
7171        "business-id-by-slug" => Ok(state_row_by_text(&root, "businesses", "slug", text("slug"))
7172            .and_then(|row| row.get("id"))
7173            .map(value_to_text)
7174            .unwrap_or_else(|| "0".to_owned())),
7175        "tenant-id-for-business-slug" => {
7176            let business_id = state_row_by_text(&root, "businesses", "slug", text("slug"))
7177                .and_then(|row| row.get("id"))
7178                .and_then(|value| value.as_i64())
7179                .unwrap_or(0);
7180            Ok(super::business::tenant_id_for_business_base(&root, business_id).to_string())
7181        }
7182        "tenant-id-for-business-id" => Ok(super::business::tenant_id_for_business_base(&root, id("business_id")).to_string()),
7183        "tenant-id-for-service-id" => {
7184            let service_id = id("service_id");
7185            let business_id = state_row_by_id(&root, "services", service_id)
7186                .and_then(|row| row.get("business_id"))
7187                .and_then(Value::as_i64)
7188                .unwrap_or(0);
7189            Ok(super::business::tenant_id_for_business_base(&root, business_id).to_string())
7190        }
7191        "tenant-id-for-technician-id" => {
7192            let business_id = state_row_by_id(&root, "technicians", id("technician_id"))
7193                .and_then(|row| row.get("business_id"))
7194                .and_then(Value::as_i64)
7195                .unwrap_or(0);
7196            Ok(super::business::tenant_id_for_business_base(&root, business_id).to_string())
7197        }
7198        "appointment-json-by-id" => output_json(state_row_by_id(&root, "appointments", id("appointment_id"))),
7199        "service-json-by-id" => output_json(state_row_by_id(&root, "services", id("service_id"))),
7200        "service-duration-minutes" => Ok(state_row_by_id(&root, "services", id("service_id"))
7201            .and_then(|row| row.get("duration_minutes"))
7202            .map(value_to_text)
7203            .unwrap_or_else(|| "45".to_owned())),
7204        "user-json-by-id" => output_json(state_row_by_id(&root, "users", id("user_id"))),
7205        "user-json-by-username" => output_json(state_row_by_text(&root, "users", "username", text("username"))),
7206        "user-json-by-email" => output_json(state_rows(&root, "users").iter().find(|row| {
7207            row.get("email").and_then(Value::as_str).is_some_and(|email| email.eq_ignore_ascii_case(text("email")))
7208        })),
7209        "business-name-by-id" | "business-slug-by-id" | "business-time-format-by-id" => {
7210            let field = match name {
7211                "business-name-by-id" => "name",
7212                "business-slug-by-id" => "slug",
7213                _ => "time_format",
7214            };
7215            Ok(state_row_by_id(&root, "businesses", id("business_id"))
7216                .and_then(|row| row.get(field))
7217                .map(value_to_text)
7218                .unwrap_or_else(|| if field == "time_format" { "am_pm" } else { "" }.to_owned()))
7219        }
7220        "business-image-url-by-slug" => Ok(state_row_by_text(&root, "businesses", "slug", text("slug"))
7221            .and_then(|row| row.get("image_url"))
7222            .map(value_to_text)
7223            .unwrap_or_default()),
7224        "service-image-url-for-business" => Ok(state_rows(&root, "services").iter().find(|row| {
7225            row.get("id").and_then(Value::as_i64) == Some(id("service_id"))
7226                && row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7227        }).and_then(|row| row.get("image_url")).map(value_to_text).unwrap_or_default()),
7228        "service-json-for-business" => output_json(state_rows(&root, "services").iter().find(|row| {
7229            row.get("id").and_then(Value::as_i64) == Some(id("service_id"))
7230                && row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7231        })),
7232        "first-service-json-for-business" => output_json(state_rows(&root, "services").iter().filter(|row| {
7233            row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7234        }).min_by_key(|row| row.get("sort_order").and_then(Value::as_i64).unwrap_or_else(|| row.get("id").and_then(Value::as_i64).unwrap_or(i64::MAX)))),
7235        "service-sort-order-for-business" => Ok(state_rows(&root, "services").iter().find(|row| {
7236            row.get("id").and_then(Value::as_i64) == Some(id("service_id"))
7237                && row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7238        }).and_then(|row| row.get("sort_order")).map(value_to_text).unwrap_or_else(|| id("service_id").max(1).to_string())),
7239        "business-availability-json-for-business" => output_json(state_rows(&root, "business_availability").iter().find(|row| {
7240            row.get("id").and_then(Value::as_i64) == Some(id("availability_id"))
7241                && row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7242        })),
7243        "technician-json-for-business" => output_json(state_rows(&root, "technicians").iter().find(|row| {
7244            row.get("id").and_then(Value::as_i64) == Some(id("technician_id"))
7245                && row.get("business_id").and_then(Value::as_i64) == Some(id("business_id"))
7246        })),
7247        "booking-json-for-user" => output_json(state_rows(&root, "bookings").iter().find(|row| {
7248            row.get("id").and_then(Value::as_i64) == Some(id("booking_id"))
7249                && row.get("user_id").and_then(Value::as_i64) == Some(id("user_id"))
7250        })),
7251        "service-booking-options-array-json" => Ok(state_row_by_id(&root, "services", id("service_id"))
7252            .and_then(|row| row.get("booking_options"))
7253            .and_then(|value| serde_json::to_string(value).ok())
7254            .unwrap_or_else(|| "[]".to_owned())),
7255        "service-booking-options-json" => {
7256            let service = state_row_by_id(&root, "services", id("service_id"));
7257            let mut rows = Vec::new();
7258            if let Some(service) = service {
7259                rows.push(serde_json::json!({
7260                    "label": service.get("name").cloned().unwrap_or(Value::String(String::new())),
7261                    "duration_minutes": service.get("duration_minutes").cloned().unwrap_or(Value::Number(45.into())),
7262                    "cost": service.get("cost").cloned().unwrap_or(Value::String(String::new())),
7263                }));
7264                if let Some(options) = service.get("booking_options").and_then(Value::as_array) {
7265                    rows.extend(options.iter().cloned());
7266                }
7267            }
7268            Ok(serde_json::to_string(&rows).unwrap_or_else(|_| "[]".to_owned()))
7269        }
7270        "service-selected-booking-option-json" => {
7271            let options = state_row_by_id(&root, "services", id("service_id"))
7272                .and_then(|row| row.get("booking_options"))
7273                .and_then(Value::as_array);
7274            let index = id("booking_option_index").max(0) as usize;
7275            output_json(options.and_then(|items| items.get(index).or_else(|| items.first())))
7276        }
7277        "active-email-verification-json" => output_json(state_active_token(&root, "email_verifications", text("token_hash"), text("now_iso"))),
7278        "active-password-reset-json" => output_json(state_active_token(&root, "password_resets", text("token_hash"), text("now_iso"))),
7279        "active-invite-json" => output_json(state_active_token(&root, "invites", text("token_hash"), text("now_iso"))),
7280        "active-session-json" => output_json(state_rows(&root, "sessions").iter().find(|row| {
7281            row.get("session_token_hash").and_then(Value::as_str) == Some(text("session_token_hash"))
7282                && row.get("revoked_at").is_none_or(|value| value.is_null() || value.as_str() == Some(""))
7283                && row.get("expires_at").and_then(Value::as_str).is_some_and(|expires| expires > text("now_iso"))
7284        })),
7285        "current-user-json" => {
7286            let user_id = state_rows(&root, "sessions").iter().find(|row| {
7287                row.get("session_token_hash").and_then(Value::as_str) == Some(text("session_token_hash"))
7288                    && row.get("revoked_at").is_none_or(|value| value.is_null() || value.as_str() == Some(""))
7289                    && row.get("expires_at").and_then(Value::as_str).is_some_and(|expires| expires > text("now_iso"))
7290            }).and_then(|row| row.get("user_id")).and_then(Value::as_i64).unwrap_or(0);
7291            output_json(state_row_by_id(&root, "users", user_id).filter(|row| row.get("is_active").and_then(Value::as_bool) != Some(false)))
7292        }
7293        "authenticate-user-json" => output_json(state_row_by_text(&root, "users", "username", text("username")).filter(|row| row.get("is_active").and_then(Value::as_bool) != Some(false))),
7294        "active-tenant-ids-lines" => Ok(state_lines(state_rows(&root, "tenants"), "id")),
7295        "user-membership-tenant-ids-json" => {
7296            let ids: Vec<Value> = state_rows(&root, "tenant_memberships").iter().filter(|row| {
7297                row.get("user_id").and_then(Value::as_i64) == Some(id("user_id"))
7298                    && !matches!(row.get("membership_status").and_then(Value::as_str), Some("disabled" | "revoked"))
7299            }).filter_map(|row| row.get("tenant_id").cloned()).collect();
7300            Ok(serde_json::to_string(&ids).unwrap_or_else(|_| "[]".to_owned()))
7301        }
7302        "next-id" => Ok(state_next_id(&root, text("section")).to_string()),
7303        "append-record" => {
7304            let section = text("section");
7305            let record = options.get("record_json").cloned().ok_or(64)?;
7306            if !record.is_object() || section.is_empty() { return Err(64); }
7307            let root_map = root.as_object_mut().ok_or(66)?;
7308            let rows = root_map.entry(section.to_owned()).or_insert_with(|| Value::Array(Vec::new()));
7309            rows.as_array_mut().ok_or(69)?.push(record);
7310            state_write(&root, state_path)
7311        }
7312        "update-record-by-id" => {
7313            let section = text("section");
7314            let record_id = id("record_id");
7315            let patch = options.get("patch_json").and_then(Value::as_object).ok_or(64)?.clone();
7316            let row = root.get_mut(section).and_then(Value::as_array_mut).and_then(|rows| rows.iter_mut().find(|row| row.get("id").and_then(Value::as_i64) == Some(record_id))).ok_or(66)?;
7317            let row_map = row.as_object_mut().ok_or(69)?;
7318            for (key, value) in patch { row_map.insert(key, value); }
7319            state_write(&root, state_path)
7320        }
7321        "remove-record-by-id" => {
7322            let section = text("section");
7323            let record_id = id("record_id");
7324            let rows = root.get_mut(section).and_then(Value::as_array_mut).ok_or(66)?;
7325            let before = rows.len();
7326            rows.retain(|row| row.get("id").and_then(Value::as_i64) != Some(record_id));
7327            if rows.len() == before { return Err(66); }
7328            state_write(&root, state_path)
7329        }
7330        "rate-limit-event-count" => {
7331            let count = state_rows(&root, "rate_limit_events").iter().filter(|row| {
7332                row.get("policy_key").and_then(Value::as_str) == Some(text("policy_key"))
7333                    && row.get("bucket_key").and_then(Value::as_str) == Some(text("bucket_key"))
7334                    && row.get("created_at").and_then(Value::as_str).is_some_and(|created| created >= text("window_start"))
7335                    && (text("ip_address").is_empty() || row.get("ip_address").and_then(Value::as_str) == Some(text("ip_address")))
7336            }).count();
7337            Ok(count.to_string())
7338        }
7339        "record-rate-limit-event" => {
7340            let event = serde_json::json!({
7341                "id": state_next_id(&root, "rate_limit_events"),
7342                "policy_key": text("policy_key"),
7343                "bucket_key": text("bucket_key"),
7344                "ip_address": if text("ip_address").is_empty() { Value::Null } else { Value::String(text("ip_address").to_owned()) },
7345                "outcome": text("outcome"),
7346                "created_at": text("created_at"),
7347            });
7348            root.as_object_mut().ok_or(66)?.entry("rate_limit_events".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?.push(event);
7349            state_write(&root, state_path)
7350        }
7351        "prune-rate-limit-events" => {
7352            let cutoff = text("cutoff_iso");
7353            root.as_object_mut().ok_or(66)?.entry("rate_limit_events".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?.retain(|row| row.get("created_at").and_then(Value::as_str).is_some_and(|created| created >= cutoff));
7354            state_write(&root, state_path)
7355        }
7356        "business-technician-ids-lines" => Ok(state_lines(&state_rows(&root, "technicians").iter().filter(|row| row.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str())).cloned().collect::<Vec<_>>(), "id")),
7357        "service-assigned-technician-ids-lines" => {
7358            let service = state_row_by_id(&root, "services", id("service_id"));
7359            let ids = service.and_then(|row| row.get("technician_ids")).and_then(Value::as_array).map(|items| items.iter().map(value_to_text).collect::<Vec<_>>().join("\n")).unwrap_or_default();
7360            Ok(ids)
7361        }
7362        "business-availability-lines" => Ok(state_rows(&root, "business_availability").iter().filter(|row| row.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str()) && (text("day_of_week").is_empty() || row.get("day_of_week").and_then(Value::as_str) == Some(text("day_of_week")))).map(|row| serde_json::to_string(row).unwrap_or_default()).collect::<Vec<_>>().join("\n")),
7363        "technician-availability-lines" => Ok(state_rows(&root, "technician_availability").iter().filter(|row| row.get("technician_id").map(value_to_text).as_deref() == Some(id("technician_id").to_string().as_str()) && (text("day_of_week").is_empty() || row.get("day_of_week").and_then(Value::as_str) == Some(text("day_of_week")))).map(|row| serde_json::to_string(row).unwrap_or_default()).collect::<Vec<_>>().join("\n")),
7364        "technician-appointments-lines" => Ok(state_rows(&root, "appointments").iter().filter(|row| row.get("technician_id").map(value_to_text).as_deref() == Some(id("technician_id").to_string().as_str()) && (text("date").is_empty() || row.get("date").and_then(Value::as_str) == Some(text("date")))).map(|row| serde_json::to_string(row).unwrap_or_default()).collect::<Vec<_>>().join("\n")),
7365        "public-business-cards-json" => Ok(serde_json::to_string(&state_rows(&root, "businesses").iter().map(|row| {
7366            serde_json::json!({ "id": row.get("id").cloned().unwrap_or(Value::Null), "slug": row.get("slug").cloned().unwrap_or(Value::String(String::new())), "name": row.get("name").cloned().unwrap_or(Value::String(String::new())), "image_url": row.get("image_url").cloned().unwrap_or(Value::String(String::new())) })
7367        }).collect::<Vec<_>>()).unwrap_or_else(|_| "[]".to_owned())),
7368        "manageable-business-cards-json" => {
7369            let tenant_ids = options.get("tenant_ids_json").and_then(Value::as_array).cloned().unwrap_or_default();
7370            let cards = state_rows(&root, "businesses").iter().filter(|business| {
7371                let business_id = business.get("id").map(value_to_text);
7372                let tenant_id = state_rows(&root, "tenants").iter().find(|tenant| tenant.get("source_business_id").map(value_to_text) == business_id).and_then(|tenant| tenant.get("id")).map(value_to_text);
7373                tenant_ids.iter().map(value_to_text).any(|wanted| tenant_id.as_deref() == Some(wanted.as_str())) || business.get("owner_id").map(value_to_text).as_deref() == Some(id("user_id").to_string().as_str())
7374            }).cloned().collect::<Vec<_>>();
7375            Ok(serde_json::to_string(&cards).unwrap_or_else(|_| "[]".to_owned()))
7376        }
7377        "managed-appointments-json" | "user-appointments-json" => {
7378            let rows = state_rows(&root, "appointments").iter().filter(|row| {
7379                if name == "user-appointments-json" { row.get("user_id").map(value_to_text).as_deref() == Some(id("user_id").to_string().as_str()) } else { true }
7380            }).cloned().collect::<Vec<_>>();
7381            Ok(serde_json::to_string(&rows).unwrap_or_else(|_| "[]".to_owned()))
7382        }
7383        "profile-page-json" => output_json(state_row_by_id(&root, "users", id("user_id"))),
7384        "appointments-page-json" => Ok(serde_json::to_string(&state_rows(&root, "appointments").iter().filter(|row| row.get("user_id").map(value_to_text).as_deref() == Some(id("user_id").to_string().as_str())).cloned().collect::<Vec<_>>()).unwrap_or_else(|_| "[]".to_owned())),
7385        "business-admin-service-rows-json" => Ok(serde_json::to_string(&state_rows(&root, "services").iter().filter(|row| row.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str())).cloned().collect::<Vec<_>>()).unwrap_or_else(|_| "[]".to_owned())),
7386        "business-admin-technician-rows-json" => Ok(serde_json::to_string(&state_rows(&root, "technicians").iter().filter(|row| row.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str())).cloned().collect::<Vec<_>>()).unwrap_or_else(|_| "[]".to_owned())),
7387        "event-stream-row-json-lines" => {
7388            let since_id = id("since_id");
7389            let limit = id("limit").clamp(1, 100) as usize;
7390            Ok(state_rows(&root, "event_stream").iter().filter(|row| row.get("id").map(value_to_text).and_then(|value| value.parse::<i64>().ok()).is_some_and(|value| value > since_id)).take(limit).map(|row| serde_json::to_string(row).unwrap_or_default()).collect::<Vec<_>>().join("\n"))
7391        }
7392        "append-audit-event" | "append-workflow-event" => {
7393            let section = if name == "append-audit-event" { "audit_log" } else { "workflow_execution_events" };
7394            let mut event = options.get("payload_json").cloned().filter(Value::is_object).unwrap_or_else(|| serde_json::json!({}));
7395            let object = event.as_object_mut().ok_or(69)?;
7396            if name == "append-audit-event" { object.insert("event".to_owned(), Value::String(text("event_kind").to_owned())); } else { object.insert("event_kind".to_owned(), Value::String(text("event_kind").to_owned())); object.insert("id".to_owned(), Value::Number(state_next_id(&root, section).into())); }
7397            object.insert("created_at".to_owned(), Value::String(text("created_at").to_owned()));
7398            root.as_object_mut().ok_or(66)?.entry(section.to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?.push(event);
7399            state_write(&root, state_path)
7400        }
7401        "issue-browser-session" => {
7402            let event = serde_json::json!({ "id": state_next_id(&root, "sessions"), "user_id": id("user_id"), "session_token_hash": text("session_token_hash"), "session_kind": "browser_session", "current_tenant_id": Value::Null, "expires_at": text("expires_at"), "revoked_at": Value::Null, "created_at": text("created_at"), "user_agent": if text("user_agent").is_empty() { Value::Null } else { Value::String(text("user_agent").to_owned()) }, "ip_address": if text("ip_address").is_empty() { Value::Null } else { Value::String(text("ip_address").to_owned()) } });
7403            root.as_object_mut().ok_or(66)?.entry("sessions".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?.push(event);
7404            state_write(&root, state_path)
7405        }
7406        "revoke-session-hash" => {
7407            let hash = text("session_token_hash").to_owned();
7408            for row in root.as_object_mut().ok_or(66)?.entry("sessions".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)? {
7409                if row.get("session_token_hash").and_then(Value::as_str) == Some(hash.as_str()) && row.get("revoked_at").is_none_or(|value| value.is_null() || value.as_str() == Some("")) { row.as_object_mut().ok_or(69)?.insert("revoked_at".to_owned(), Value::String(text("revoked_at").to_owned())); }
7410            }
7411            state_write(&root, state_path)
7412        }
7413        "issue-email-verification" | "issue-password-reset" => {
7414            let section = if name == "issue-email-verification" { "email_verifications" } else { "password_resets" };
7415            let user_id = id("user_id");
7416            let next_id = state_next_id(&root, section);
7417            let token_hash = text("token_hash").to_owned();
7418            let expires_at = text("expires_at").to_owned();
7419            let created_at = text("created_at").to_owned();
7420            let rows = root.as_object_mut().ok_or(66)?.entry(section.to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?;
7421            rows.retain(|row| row.get("user_id").map(value_to_text).and_then(|value| value.parse::<i64>().ok()) != Some(user_id) || !row.get("claimed_at").is_none_or(|value| value.is_null() || value.as_str() == Some("")));
7422            rows.push(serde_json::json!({ "id": next_id, "user_id": user_id, "token_hash": token_hash, "expires_at": expires_at, "claimed_at": Value::Null, "created_at": created_at }));
7423            state_write(&root, state_path)
7424        }
7425        "claim-email-verification" => {
7426            let verification_id = id("verification_id");
7427            for row in root.as_object_mut().ok_or(66)?.entry("email_verifications".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)? { if row.get("id").map(value_to_text).and_then(|value| value.parse::<i64>().ok()) == Some(verification_id) { row.as_object_mut().ok_or(69)?.insert("claimed_at".to_owned(), Value::String(text("claimed_at").to_owned())); } }
7428            if let Some(user) = state_row_by_id(&root, "users", id("user_id")).cloned() { let _ = user; }
7429            state_write(&root, state_path)
7430        }
7431        "issue-invite" => {
7432            let email = text("email").to_owned();
7433            let kind = text("invite_kind").to_owned();
7434            let next_id = state_next_id(&root, "invites");
7435            let account_type = text("account_type").to_owned();
7436            let token_hash = text("token_hash").to_owned();
7437            let expires_at = text("expires_at").to_owned();
7438            let created_at = text("created_at").to_owned();
7439            let rows = root.as_object_mut().ok_or(66)?.entry("invites".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)?;
7440            rows.retain(|row| !(row.get("email").and_then(Value::as_str).is_some_and(|value| value.eq_ignore_ascii_case(&email)) && row.get("invite_kind").and_then(Value::as_str) == Some(kind.as_str()) && row.get("claimed_at").is_none_or(|value| value.is_null() || value.as_str() == Some(""))));
7441            rows.push(serde_json::json!({ "id": next_id, "email": email, "account_type": account_type, "invite_kind": kind, "token_hash": token_hash, "expires_at": expires_at, "claimed_at": Value::Null, "created_at": created_at, "target_tenant_id": if id("target_tenant_id") > 0 { Value::Number(id("target_tenant_id").into()) } else { Value::Null }, "role_hint": if text("role_hint").is_empty() { Value::Null } else { Value::String(text("role_hint").to_owned()) }, "invited_by_user_id": if id("invited_by_user_id") > 0 { Value::Number(id("invited_by_user_id").into()) } else { Value::Null }, "accepted_user_id": Value::Null }));
7442            state_write(&root, state_path)
7443        }
7444        "claim-invite" => {
7445            let invite_id = id("invite_id");
7446            for row in root.as_object_mut().ok_or(66)?.entry("invites".to_owned()).or_insert_with(|| Value::Array(Vec::new())).as_array_mut().ok_or(69)? { if row.get("id").map(value_to_text).and_then(|value| value.parse::<i64>().ok()) == Some(invite_id) { let object = row.as_object_mut().ok_or(69)?; object.insert("accepted_user_id".to_owned(), Value::Number(id("accepted_user_id").into())); object.insert("claimed_at".to_owned(), Value::String(text("claimed_at").to_owned())); } }
7447            state_write(&root, state_path)
7448        }
7449        "business-open-for-slot" => {
7450            let business_id = id("business_id");
7451            let day = text("date");
7452            let open = state_rows(&root, "business_availability").iter().any(|row| row.get("business_id").map(value_to_text).as_deref() == Some(business_id.to_string().as_str()) && (day.is_empty() || row.get("date").and_then(Value::as_str).is_none_or(|value| value == day)));
7453            Ok(if open { "1" } else { "0" }.to_owned())
7454        }
7455        "technician-booked-for-slot" => {
7456            let booked = state_rows(&root, "appointments").iter().any(|row| row.get("technician_id").map(value_to_text).as_deref() == Some(id("technician_id").to_string().as_str()) && row.get("date").and_then(Value::as_str) == Some(text("date")) && row.get("time").and_then(Value::as_str) == Some(text("time")));
7457            Ok(if booked { "1" } else { "0" }.to_owned())
7458        }
7459        "assign-technician-for-slot" => {
7460            let selected = state_rows(&root, "technicians").iter().find(|technician| {
7461                technician.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str()) && !state_rows(&root, "appointments").iter().any(|appointment| appointment.get("technician_id").map(value_to_text) == technician.get("id").map(value_to_text) && appointment.get("date").and_then(Value::as_str) == Some(text("date")) && appointment.get("time").and_then(Value::as_str) == Some(text("time")))
7462            });
7463            Ok(selected.and_then(|row| row.get("id")).map(value_to_text).unwrap_or_else(|| "0".to_owned()))
7464        }
7465        "google-calendar-connection-for-business" => output_json(state_rows(&root, "google_calendar_connections").iter().find(|row| row.get("business_id").map(value_to_text).as_deref() == Some(id("business_id").to_string().as_str()))),
7466        "business-dashboard-page-json" | "explore-page-json" | "business-admin-page-json" => {
7467            let slug = text("slug");
7468            let business = if slug.is_empty() { None } else { state_row_by_text(&root, "businesses", "slug", slug) };
7469            Ok(serde_json::to_string(&serde_json::json!({
7470                "business": business,
7471                "businesses": state_rows(&root, "businesses"),
7472                "services": business.map(|row| state_rows(&root, "services").iter().filter(|service| service.get("business_id").map(value_to_text) == row.get("id").map(value_to_text)).cloned().collect::<Vec<_>>()).unwrap_or_default(),
7473                "technicians": business.map(|row| state_rows(&root, "technicians").iter().filter(|technician| technician.get("business_id").map(value_to_text) == row.get("id").map(value_to_text)).cloned().collect::<Vec<_>>()).unwrap_or_default(),
7474            })).unwrap_or_else(|_| "{}".to_owned()))
7475        }
7476        "business-public-page-json" | "business-edit-page-json" | "business-public-render-page-json" => output_json(state_row_by_text(&root, "businesses", "slug", text("slug"))),
7477        "service-edit-page-json" | "service-book-form-page-json" => output_json(state_row_by_id(&root, "services", id("service_id"))),
7478        "business-calendar-page-json" | "business-calendar-render-page-json" => Ok(serde_json::to_string(&state_rows(&root, "appointments").iter().filter(|row| row.get("business_id").map(value_to_text).as_deref() == state_row_by_text(&root, "businesses", "slug", text("slug")).and_then(|business| business.get("id")).map(value_to_text).as_deref()).cloned().collect::<Vec<_>>()).unwrap_or_else(|_| "[]".to_owned())),
7479        "profile-render-page-json" => output_json(state_row_by_id(&root, "users", id("user_id"))),
7480        "service-visual-html" => service_visual_html(Path::new(text("app_root")), Some(text("image_url")), text("service_name"), Some(text("primary_color"))).ok_or(69),
7481        "service-sort-order-options-html" => service_sort_order_options_html(Path::new(text("app_root")), &root, id("business_id"), id("selected_order"), id("include_append") != 0).ok_or(69),
7482        "service-booking-options-editor-html" => service_booking_options_editor_html(Path::new(text("app_root")), &root, id("service_id")).ok_or(69),
7483        "service-technician-checkboxes-html" => technician_checkboxes_html(Path::new(text("app_root")), &root, id("business_id"), id("service_id"), text("empty_message"), false).ok_or(69),
7484        "business-technician-checkboxes-html" => technician_checkboxes_html(Path::new(text("app_root")), &root, id("business_id"), 0, text("empty_message"), true).ok_or(69),
7485        _ => Err(78),
7486    }
7487}
7488
7489/// Performs generated surface context value.
7490fn generated_surface_context_value(surface: &Value, params: &Value) -> Option<(String, String)> {
7491    let binding = surface.get("context_binding")?;
7492    let param = binding
7493        .get("param")
7494        .and_then(Value::as_str)
7495        .filter(|value| !value.is_empty())?;
7496    let value = params
7497        .get(param)
7498        .map(value_to_text)
7499        .filter(|value| !value.is_empty())?;
7500    Some((param.to_owned(), value))
7501}
7502
7503/// Resolves generated-surface context, tenant scope, and context record metadata.
7504///
7505/// # Parameters
7506///
7507/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_context_json`].
7508/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_context_json`].
7509/// - `params_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_context_json`].
7510///
7511/// # Returns
7512///
7513/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_context_json`] can produce a value and [`None`] otherwise.
7514///
7515/// # Performance
7516///
7517/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_context_json`].
7518///
7519/// # Examples
7520///
7521/// ```rust,ignore
7522/// let _result = pharos_native::runtime::json_commands::generated_surface_context_json(todo!(), "{}", todo!());
7523/// ```
7524///
7525/// # Related
7526///
7527/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7528pub fn generated_surface_context_json(
7529    state_path: &Path,
7530    surface_json: &str,
7531    params_json: &str,
7532) -> Option<String> {
7533    let state = read_json_file(state_path)?;
7534    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
7535    let params = serde_json::from_str::<Value>(params_json).ok()?;
7536    let binding = surface.get("context_binding");
7537    let Some((param, context_value)) = generated_surface_context_value(&surface, &params) else {
7538        return serde_json::to_string(&serde_json::json!({
7539            "ok": false,
7540            "error_code": "missing_context_parameter",
7541            "message": "Missing route parameter."
7542        }))
7543        .ok();
7544    };
7545    let state_collection = binding
7546        .and_then(|value| value.get("state_collection"))
7547        .and_then(Value::as_str)
7548        .unwrap_or("businesses");
7549    let match_field = binding
7550        .and_then(|value| value.get("match_field"))
7551        .and_then(Value::as_str)
7552        .unwrap_or("slug");
7553    let record = state_row_by_text(&state, state_collection, match_field, &context_value)?;
7554    let context_id_field = binding
7555        .and_then(|value| value.get("context_id_field"))
7556        .and_then(Value::as_str)
7557        .unwrap_or("id");
7558    let label_field = binding
7559        .and_then(|value| value.get("context_label_field"))
7560        .and_then(Value::as_str)
7561        .unwrap_or("name");
7562    let context_id = record.get(context_id_field).cloned().unwrap_or(Value::Null);
7563    let tenant_collection = binding
7564        .and_then(|value| value.get("tenant_collection"))
7565        .and_then(Value::as_str)
7566        .unwrap_or("tenants");
7567    let tenant_match_field = binding
7568        .and_then(|value| value.get("tenant_match_field"))
7569        .and_then(Value::as_str)
7570        .unwrap_or("source_business_id");
7571    let tenant_match_from = binding
7572        .and_then(|value| value.get("tenant_match_from_context_field"))
7573        .and_then(Value::as_str)
7574        .unwrap_or("id");
7575    let tenant_value = record
7576        .get(tenant_match_from)
7577        .map(value_to_text)
7578        .unwrap_or_default();
7579    let tenant_id = state_rows(&state, tenant_collection)
7580        .iter()
7581        .find(|row| {
7582            row.get(tenant_match_field).map(value_to_text).as_deref() == Some(tenant_value.as_str())
7583        })
7584        .and_then(|row| row.get("id"))
7585        .cloned()
7586        .unwrap_or(Value::Number(0.into()));
7587    let tenant_id_text = value_to_text(&tenant_id);
7588    serde_json::to_string(&serde_json::json!({
7589        "ok": true,
7590        "tenant_id": tenant_id,
7591        "tenant_scope": if tenant_id_text == "0" || tenant_id_text.is_empty() { "global".to_owned() } else { format!("tenant:{tenant_id_text}") },
7592        "context_id": context_id,
7593        "context_param": param,
7594        "context_value": context_value,
7595        "context_label": record.get(label_field).map(value_to_text).unwrap_or_default(),
7596        "record": record,
7597    })).ok()
7598}
7599
7600/// Performs generated surface filter matches.
7601fn generated_surface_filter_matches(item: &Value, filter: &Value, raw_query: &str) -> bool {
7602    let query = filter
7603        .get("query")
7604        .and_then(Value::as_str)
7605        .unwrap_or_default();
7606    if query.is_empty() {
7607        return true;
7608    }
7609    let wanted =
7610        request_query_value(raw_query, query).or_else(|| filter.get("default").map(value_to_text));
7611    let Some(wanted) = wanted.filter(|value| !value.is_empty() && value != "all") else {
7612        return true;
7613    };
7614    let field = filter.get("field").and_then(Value::as_str).unwrap_or(query);
7615    let actual = item.get(field);
7616    match filter
7617        .get("match")
7618        .and_then(Value::as_str)
7619        .unwrap_or("exact")
7620    {
7621        "contains" => actual.map(value_to_text).is_some_and(|value| {
7622            value
7623                .to_ascii_lowercase()
7624                .contains(&wanted.to_ascii_lowercase())
7625        }),
7626        "boolean" => actual
7627            .map(value_to_text)
7628            .is_some_and(|value| value.eq_ignore_ascii_case(&wanted)),
7629        "array_contains_integer" => actual.and_then(Value::as_array).is_some_and(|values| {
7630            values
7631                .iter()
7632                .map(value_to_text)
7633                .any(|value| value == wanted)
7634        }),
7635        _ => actual
7636            .map(value_to_text)
7637            .is_some_and(|value| value == wanted),
7638    }
7639}
7640
7641/// Builds a filtered, sorted, paginated generated-surface list result.
7642///
7643/// # Parameters
7644///
7645/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_result_json`].
7646/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_result_json`].
7647/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_result_json`].
7648/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_result_json`].
7649///
7650/// # Returns
7651///
7652/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_list_result_json`] can produce a value and [`None`] otherwise.
7653///
7654/// # Performance
7655///
7656/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_list_result_json`].
7657///
7658/// # Examples
7659///
7660/// ```rust,ignore
7661/// let _result = pharos_native::runtime::json_commands::generated_surface_list_result_json(todo!(), "{}", todo!(), todo!());
7662/// ```
7663///
7664/// # Related
7665///
7666/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7667pub fn generated_surface_list_result_json(
7668    state_path: &Path,
7669    surface_json: &str,
7670    context_json: &str,
7671    raw_query: &str,
7672) -> Option<String> {
7673    let state = read_json_file(state_path)?;
7674    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
7675    let context = serde_json::from_str::<Value>(context_json).ok()?;
7676    let collection = surface.get("entity_collection").and_then(Value::as_str)?;
7677    let scope_field = surface.get("scope_field").and_then(Value::as_str);
7678    let context_id = context
7679        .get("context_id")
7680        .map(value_to_text)
7681        .unwrap_or_default();
7682    let mut rows: Vec<Value> = state_rows(&state, collection)
7683        .iter()
7684        .filter(|row| {
7685            let scope_matches = scope_field
7686                .map(|field| {
7687                    row.get(field).map(value_to_text).as_deref() == Some(context_id.as_str())
7688                })
7689                .unwrap_or(true);
7690            scope_matches
7691                && surface
7692                    .get("filters")
7693                    .and_then(Value::as_array)
7694                    .map(|filters| {
7695                        filters
7696                            .iter()
7697                            .all(|filter| generated_surface_filter_matches(row, filter, raw_query))
7698                    })
7699                    .unwrap_or(true)
7700        })
7701        .cloned()
7702        .collect();
7703    let sort_key = request_query_value(raw_query, "sort").or_else(|| {
7704        surface
7705            .get("default_sort")
7706            .and_then(Value::as_str)
7707            .map(ToOwned::to_owned)
7708    });
7709    if let Some(sort_key) = sort_key.clone().filter(|value| !value.is_empty()) {
7710        let descending = sort_key.starts_with('-');
7711        let field = sort_key.trim_start_matches('-').to_owned();
7712        rows.sort_by(|left, right| {
7713            let ordering = value_to_text(left.get(&field).unwrap_or(&Value::Null))
7714                .cmp(&value_to_text(right.get(&field).unwrap_or(&Value::Null)));
7715            if descending {
7716                ordering.reverse()
7717            } else {
7718                ordering
7719            }
7720        });
7721    }
7722    let page = request_query_value(raw_query, "page")
7723        .and_then(|value| value.parse::<usize>().ok())
7724        .filter(|value| *value > 0)
7725        .unwrap_or(1);
7726    let page_default = surface
7727        .get("page_size_default")
7728        .and_then(Value::as_u64)
7729        .unwrap_or(25) as usize;
7730    let page_max = surface
7731        .get("page_size_max")
7732        .and_then(Value::as_u64)
7733        .unwrap_or(100) as usize;
7734    let page_size = request_query_value(raw_query, "page_size")
7735        .and_then(|value| value.parse::<usize>().ok())
7736        .filter(|value| *value > 0)
7737        .unwrap_or(page_default)
7738        .min(page_max);
7739    let total_items = rows.len();
7740    let start = page
7741        .saturating_sub(1)
7742        .saturating_mul(page_size)
7743        .min(total_items);
7744    let end = start.saturating_add(page_size).min(total_items);
7745    let response_fields = surface.get("response_fields").and_then(Value::as_array);
7746    let items: Vec<Value> = rows[start..end]
7747        .iter()
7748        .map(|row| {
7749            if let Some(fields) = response_fields {
7750                let mut object = serde_json::Map::new();
7751                for field in fields.iter().filter_map(Value::as_str) {
7752                    object.insert(
7753                        field.to_owned(),
7754                        row.get(field).cloned().unwrap_or(Value::Null),
7755                    );
7756                }
7757                Value::Object(object)
7758            } else {
7759                row.clone()
7760            }
7761        })
7762        .collect();
7763    serde_json::to_string(&serde_json::json!({
7764        "items": items,
7765        "pagination": { "page": page, "page_size": page_size, "total_items": total_items, "total_pages": if page_size == 0 { 1 } else { total_items.div_ceil(page_size) } },
7766        "sort": sort_key,
7767    })).ok()
7768}
7769
7770/// Builds a default generated-surface candidate from existing, declared, and submitted values.
7771///
7772/// # Parameters
7773///
7774/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7775/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7776/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7777/// - `existing_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7778/// - `submitted_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7779///
7780/// # Returns
7781///
7782/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_default_candidate_json`] can produce a value and [`None`] otherwise.
7783///
7784/// # Performance
7785///
7786/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_default_candidate_json`].
7787///
7788/// # Examples
7789///
7790/// ```rust,ignore
7791/// let _result = pharos_native::runtime::json_commands::generated_surface_default_candidate_json(todo!(), "{}", todo!(), todo!(), todo!());
7792/// ```
7793///
7794/// # Related
7795///
7796/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7797pub fn generated_surface_default_candidate_json(
7798    state_path: &Path,
7799    surface_json: &str,
7800    context_json: &str,
7801    existing_json: Option<&str>,
7802    submitted_json: Option<&str>,
7803) -> Option<String> {
7804    let state = read_json_file(state_path)?;
7805    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
7806    let context = serde_json::from_str::<Value>(context_json).ok()?;
7807    let mut candidate = serde_json::Map::new();
7808    for source in [existing_json, None] {
7809        if let Some(text) = source.filter(|value| !value.is_empty())
7810            && let Some(object) = serde_json::from_str::<Value>(text).ok()?.as_object()
7811        {
7812            candidate.extend(object.clone());
7813        }
7814    }
7815    if let Some(defaults) = surface.get("defaults").and_then(Value::as_object) {
7816        for (key, value) in defaults {
7817            candidate
7818                .entry(key.clone())
7819                .or_insert_with(|| value.clone());
7820        }
7821    }
7822    if let Some(text) = submitted_json.filter(|value| !value.is_empty())
7823        && let Some(object) = serde_json::from_str::<Value>(text).ok()?.as_object()
7824    {
7825        candidate.extend(object.clone());
7826    }
7827    if let Some(scope_field) = surface
7828        .get("scope_field")
7829        .and_then(Value::as_str)
7830        .filter(|value| !value.is_empty())
7831        && let Some(context_id) = context.get("context_id")
7832    {
7833        candidate.insert(scope_field.to_owned(), context_id.clone());
7834    }
7835    if existing_json.is_none()
7836        && let (Some(sequence_field), Some(collection)) = (
7837            surface.get("auto_sequence_field").and_then(Value::as_str),
7838            surface.get("entity_collection").and_then(Value::as_str),
7839        )
7840    {
7841        let scope_field = surface.get("scope_field").and_then(Value::as_str);
7842        let context_id = context
7843            .get("context_id")
7844            .map(value_to_text)
7845            .unwrap_or_default();
7846        let next = state_rows(&state, collection)
7847            .iter()
7848            .filter(|row| {
7849                scope_field
7850                    .map(|field| {
7851                        row.get(field).map(value_to_text).as_deref() == Some(context_id.as_str())
7852                    })
7853                    .unwrap_or(true)
7854            })
7855            .filter_map(|row| {
7856                row.get(sequence_field)
7857                    .map(value_to_text)
7858                    .and_then(|value| value.parse::<i64>().ok())
7859            })
7860            .max()
7861            .unwrap_or(0)
7862            + 1;
7863        candidate.insert(sequence_field.to_owned(), Value::Number(next.into()));
7864    }
7865    generated::generated_surface_coerce_candidate_json(
7866        &surface,
7867        &serde_json::to_string(&candidate).ok()?,
7868    )
7869    .or_else(|| serde_json::to_string(&candidate).ok())
7870}
7871
7872/// Renders generated-surface form controls from the app-owned form declaration.
7873///
7874/// # Parameters
7875///
7876/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7877/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7878/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7879/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7880/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7881/// - `item_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7882///
7883/// # Returns
7884///
7885/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_form_fields_html`] can produce a value and [`None`] otherwise.
7886///
7887/// # Performance
7888///
7889/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_form_fields_html`].
7890///
7891/// # Examples
7892///
7893/// ```rust,ignore
7894/// let _result = pharos_native::runtime::json_commands::generated_surface_form_fields_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), "{}");
7895/// ```
7896///
7897/// # Related
7898///
7899/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7900pub fn generated_surface_form_fields_html(
7901    app_root: &Path,
7902    state_path: &Path,
7903    fixture_path: &Path,
7904    surface_json: &str,
7905    context_json: &str,
7906    item_json: Option<&str>,
7907) -> Option<String> {
7908    let _state = read_json_file(state_path)?;
7909    let fixture = read_json_file(fixture_path)?;
7910    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
7911    let _context = serde_json::from_str::<Value>(context_json).ok()?;
7912    let item = item_json
7913        .filter(|value| !value.is_empty())
7914        .and_then(|value| serde_json::from_str::<Value>(value).ok())
7915        .unwrap_or_else(|| serde_json::json!({}));
7916    let form_id = surface.get("form_id").and_then(Value::as_str)?;
7917    let form = fixture
7918        .get("forms")
7919        .and_then(Value::as_array)?
7920        .iter()
7921        .find(|form| form.get("form_id").and_then(Value::as_str) == Some(form_id))?;
7922    let mut out = String::new();
7923    for field in form.get("fields").and_then(Value::as_array)? {
7924        let field_id = field
7925            .get("field_id")
7926            .and_then(Value::as_str)
7927            .filter(|value| !value.is_empty())?;
7928        let widget = field
7929            .get("widget")
7930            .and_then(Value::as_str)
7931            .unwrap_or("text");
7932        let label = field
7933            .get("label")
7934            .and_then(Value::as_str)
7935            .filter(|value| !value.is_empty())
7936            .map(ToOwned::to_owned)
7937            .unwrap_or_else(|| generated_surface_label(field_id));
7938        let value = item.get(field_id).map(value_to_text).unwrap_or_default();
7939        let options = if widget == "select" {
7940            generated_surface_select_options_html(
7941                app_root,
7942                &serde_json::to_string(field).ok()?,
7943                Some(&value),
7944            )?
7945        } else {
7946            String::new()
7947        };
7948        out.push_str(&render_ui_element_html(
7949            app_root,
7950            if widget == "select" {
7951                "select"
7952            } else if widget == "textarea" {
7953                "textarea"
7954            } else if widget == "checkbox" {
7955                "checkbox"
7956            } else {
7957                "input"
7958            },
7959            Some(widget),
7960            field_id,
7961            field_id,
7962            &label,
7963            &value,
7964            &options,
7965        )?);
7966    }
7967    Some(out)
7968}
7969
7970/// Renders relation checkbox options and the app-owned checkbox group fragment.
7971///
7972/// # Parameters
7973///
7974/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7975/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7976/// - `relation_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7977/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7978/// - `selected_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7979///
7980/// # Returns
7981///
7982/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`] can produce a value and [`None`] otherwise.
7983///
7984/// # Performance
7985///
7986/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_relation_checkboxes_html`].
7987///
7988/// # Examples
7989///
7990/// ```rust,ignore
7991/// let _result = pharos_native::runtime::json_commands::generated_surface_relation_checkboxes_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
7992/// ```
7993///
7994/// # Related
7995///
7996/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
7997pub fn generated_surface_relation_checkboxes_html(
7998    app_root: &Path,
7999    state_path: &Path,
8000    relation_json: &str,
8001    context_json: &str,
8002    selected_json: Option<&str>,
8003) -> Option<String> {
8004    let state = read_json_file(state_path)?;
8005    let relation = serde_json::from_str::<Value>(relation_json).ok()?;
8006    let context = serde_json::from_str::<Value>(context_json).ok()?;
8007    let selected = selected_json
8008        .and_then(|text| serde_json::from_str::<Value>(text).ok())
8009        .unwrap_or_else(|| Value::Array(Vec::new()));
8010    let relation_field = relation
8011        .get("field")
8012        .and_then(Value::as_str)
8013        .unwrap_or("relation");
8014    let collection = relation
8015        .get("related_collection")
8016        .and_then(Value::as_str)
8017        .unwrap_or_default();
8018    let scope_field = relation.get("related_scope_field").and_then(Value::as_str);
8019    let context_id = context
8020        .get("context_id")
8021        .map(value_to_text)
8022        .unwrap_or_default();
8023    let label_field = relation
8024        .get("label_field")
8025        .and_then(Value::as_str)
8026        .unwrap_or("name");
8027    let prefix = relation
8028        .get("form_checkbox_prefix")
8029        .and_then(Value::as_str)
8030        .filter(|value| !value.is_empty())
8031        .unwrap_or(relation_field);
8032    let mut options_html = String::new();
8033    for row in state_rows(&state, collection) {
8034        if !scope_field
8035            .map(|field| row.get(field).map(value_to_text).as_deref() == Some(context_id.as_str()))
8036            .unwrap_or(true)
8037        {
8038            continue;
8039        }
8040        let row_id = row
8041            .get("id")
8042            .map(value_to_text)
8043            .filter(|value| !value.is_empty())?;
8044        let row_label = row
8045            .get(label_field)
8046            .map(value_to_text)
8047            .filter(|value| !value.is_empty())
8048            .unwrap_or_else(|| row_id.clone());
8049        let selected = selected
8050            .as_array()
8051            .map(|items| items.iter().map(value_to_text).any(|value| value == row_id))
8052            .unwrap_or(false);
8053        let params = super::ui::ui_render_param_map(
8054            &format!("{prefix}{row_id}"),
8055            Some("checkbox"),
8056            Some("button"),
8057            &format!("{prefix}{row_id}"),
8058            &row_label,
8059            &row_label,
8060            &row_id,
8061            Some(""),
8062            Some(""),
8063            if selected { " checked" } else { "" },
8064            "",
8065            "",
8066            &row_label,
8067            "checkbox",
8068        )?;
8069        options_html.push_str(
8070            &generated::render_generated_admin_fragment_from_value_runtime(
8071                app_root,
8072                "templates/shared/fragments/ui_checkbox.html",
8073                &params,
8074            )?,
8075        );
8076    }
8077    if options_html.is_empty() {
8078        options_html.push_str(&render_fragment_with_params(
8079            app_root,
8080            "templates/shared/fragments/muted_text.html",
8081            serde_json::Map::from_iter([(
8082                "message".to_owned(),
8083                Value::String(
8084                    relation
8085                        .get("empty_options_text")
8086                        .and_then(Value::as_str)
8087                        .unwrap_or("No related records available.")
8088                        .to_owned(),
8089                ),
8090            )]),
8091        )?);
8092    }
8093    render_fragment_with_params(
8094        app_root,
8095        "templates/shared/fragments/ui_checkbox_group.html",
8096        serde_json::Map::from_iter([
8097            ("id".to_owned(), Value::String(relation_field.to_owned())),
8098            (
8099                "class_name".to_owned(),
8100                Value::String("form-group".to_owned()),
8101            ),
8102            (
8103                "label".to_owned(),
8104                Value::String(
8105                    relation
8106                        .get("label")
8107                        .and_then(Value::as_str)
8108                        .unwrap_or(relation_field)
8109                        .to_owned(),
8110                ),
8111            ),
8112            ("help_html".to_owned(), Value::String(String::new())),
8113            ("options_html".to_owned(), Value::String(options_html)),
8114        ]),
8115    )
8116}
8117
8118/// Builds the generated-admin table fragments and column count.
8119///
8120/// # Parameters
8121///
8122/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_table_json`].
8123/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_table_json`].
8124/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_table_json`].
8125/// - `list_result_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_table_json`].
8126///
8127/// # Returns
8128///
8129/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_manage_table_json`] can produce a value and [`None`] otherwise.
8130///
8131/// # Performance
8132///
8133/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_manage_table_json`].
8134///
8135/// # Examples
8136///
8137/// ```rust,ignore
8138/// let _result = pharos_native::runtime::json_commands::generated_surface_manage_table_json(std::path::Path::new("apps/dev_docs"), "{}", todo!(), todo!());
8139/// ```
8140///
8141/// # Related
8142///
8143/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8144pub fn generated_surface_manage_table_json(
8145    app_root: &Path,
8146    surface_json: &str,
8147    context_json: &str,
8148    list_result_json: &str,
8149) -> Option<String> {
8150    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
8151    let list = serde_json::from_str::<Value>(list_result_json).ok()?;
8152    let columns = surface
8153        .get("admin")
8154        .and_then(|value| value.get("list_columns"))
8155        .cloned()
8156        .or_else(|| surface.get("response_fields").cloned())
8157        .unwrap_or_else(|| Value::Array(Vec::new()));
8158    let mut header = String::new();
8159    if !generated::runtime_generated_surface_append_table_header_cells_html(
8160        &mut header,
8161        &columns,
8162        app_root,
8163    ) {
8164        return None;
8165    }
8166    let fields: Vec<String> = columns
8167        .as_array()
8168        .map(|items| {
8169            items
8170                .iter()
8171                .filter_map(|item| {
8172                    item.get("field")
8173                        .and_then(Value::as_str)
8174                        .or_else(|| item.as_str())
8175                })
8176                .map(ToOwned::to_owned)
8177                .collect()
8178        })
8179        .unwrap_or_default();
8180    let mut rows_html = String::new();
8181    for row in list.get("items").and_then(Value::as_array)? {
8182        let mut cells = String::new();
8183        for field in &fields {
8184            let field_value =
8185                html_escape_text(&value_to_text(row.get(field).unwrap_or(&Value::Null)));
8186            let cell = render_fragment_with_params(
8187                app_root,
8188                "templates/generated_admin/fragments/table_row_cell.html",
8189                serde_json::Map::from_iter([(
8190                    "field_value".to_owned(),
8191                    Value::String(field_value),
8192                )]),
8193            )?;
8194            cells.push_str(&cell);
8195        }
8196        rows_html.push_str(&render_fragment_with_params(
8197            app_root,
8198            "templates/generated_admin/fragments/table_row.html",
8199            serde_json::Map::from_iter([
8200                ("cells_html".to_owned(), Value::String(cells)),
8201                ("action_cell_html".to_owned(), Value::String(String::new())),
8202            ]),
8203        )?);
8204    }
8205    let _ = context_json;
8206    serde_json::to_string(&serde_json::json!({ "header_html": header, "row_html": rows_html, "column_count": fields.len() })).ok()
8207}
8208
8209/// Builds the generated-admin manage-page JSON contract.
8210///
8211/// # Parameters
8212///
8213/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8214/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8215/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8216/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8217/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8218/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8219///
8220/// # Returns
8221///
8222/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_manage_page_json`] can produce a value and [`None`] otherwise.
8223///
8224/// # Performance
8225///
8226/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_manage_page_json`].
8227///
8228/// # Examples
8229///
8230/// ```rust,ignore
8231/// let _result = pharos_native::runtime::json_commands::generated_surface_manage_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), todo!());
8232/// ```
8233///
8234/// # Related
8235///
8236/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8237pub fn generated_surface_manage_page_json(
8238    app_root: &Path,
8239    state_path: &Path,
8240    fixture_path: &Path,
8241    surface_json: &str,
8242    context_json: &str,
8243    raw_query: &str,
8244) -> Option<String> {
8245    let list_result =
8246        generated_surface_list_result_json(state_path, surface_json, context_json, raw_query)?;
8247    let table =
8248        generated_surface_manage_table_json(app_root, surface_json, context_json, &list_result)?;
8249    let form_fields = generated_surface_form_fields_html(
8250        app_root,
8251        state_path,
8252        fixture_path,
8253        surface_json,
8254        context_json,
8255        None,
8256    )?;
8257    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
8258    let context = serde_json::from_str::<Value>(context_json).ok()?;
8259    let path_for = |operation: &str| {
8260        let context_value = surface
8261            .get("context_binding")
8262            .and_then(|value| value.get("param"))
8263            .and_then(Value::as_str)
8264            .and_then(|param| context.get(param))
8265            .map(value_to_text);
8266        generated::runtime_generated_surface_operation_path(
8267            &surface,
8268            context_value.as_deref(),
8269            operation,
8270            None,
8271        )
8272        .unwrap_or_default()
8273    };
8274    serde_json::to_string(&serde_json::json!({
8275        "title": surface.get("admin").and_then(|value| value.get("manage_title")).and_then(Value::as_str).unwrap_or("Manage records"),
8276        "manage_path": path_for("manage"),
8277        "create_path": path_for("create"),
8278        "back_path": path_for("manage"),
8279        "list_result": serde_json::from_str::<Value>(&list_result).ok()?,
8280        "manage_table": serde_json::from_str::<Value>(&table).ok()?,
8281        "form_fields_html": form_fields,
8282        "filter_controls_html": generated_surface_filter_controls_html(app_root, surface_json, raw_query).unwrap_or_default(),
8283        "sort_options_html": generated_surface_sort_options_html(app_root, surface_json, raw_query).unwrap_or_default(),
8284    })).ok()
8285}
8286
8287/// Renders the service visual using the app-owned image or badge fragment.
8288///
8289/// # Parameters
8290///
8291/// - `app_root`: Input consumed by [`crate::runtime::json_commands::service_visual_html`].
8292/// - `image_url`: Input consumed by [`crate::runtime::json_commands::service_visual_html`].
8293/// - `service_name`: Input consumed by [`crate::runtime::json_commands::service_visual_html`].
8294/// - `primary_color`: Input consumed by [`crate::runtime::json_commands::service_visual_html`].
8295///
8296/// # Returns
8297///
8298/// Returns [`Some`] when [`crate::runtime::json_commands::service_visual_html`] can produce a value and [`None`] otherwise.
8299///
8300/// # Performance
8301///
8302/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::service_visual_html`].
8303///
8304/// # Examples
8305///
8306/// ```rust,ignore
8307/// let _result = pharos_native::runtime::json_commands::service_visual_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
8308/// ```
8309///
8310/// # Related
8311///
8312/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8313pub fn service_visual_html(
8314    app_root: &Path,
8315    image_url: Option<&str>,
8316    service_name: &str,
8317    primary_color: Option<&str>,
8318) -> Option<String> {
8319    if let Some(image_url) = image_url.filter(|value| !value.is_empty() && *value != "null") {
8320        return render_fragment_with_params(
8321            app_root,
8322            "templates/shared/fragments/visual_image.html",
8323            serde_json::Map::from_iter([
8324                (
8325                    "wrapper_class".to_owned(),
8326                    Value::String("service-visual service-visual-image".to_owned()),
8327                ),
8328                ("image_url".to_owned(), Value::String(image_url.to_owned())),
8329                (
8330                    "image_alt".to_owned(),
8331                    Value::String(service_name.to_owned()),
8332                ),
8333            ]),
8334        );
8335    }
8336    let initials = dynamic_service_abbreviation(service_name);
8337    render_fragment_with_params(
8338        app_root,
8339        "templates/shared/fragments/visual_badge.html",
8340        serde_json::Map::from_iter([
8341            (
8342                "wrapper_class".to_owned(),
8343                Value::String("service-visual service-visual-badge".to_owned()),
8344            ),
8345            (
8346                "style_attr".to_owned(),
8347                Value::String(format!(
8348                    "background:{};color:#fff;",
8349                    primary_color
8350                        .filter(|value| !value.is_empty())
8351                        .unwrap_or("#2563eb")
8352                )),
8353            ),
8354            (
8355                "text_value".to_owned(),
8356                Value::String(if initials.is_empty() {
8357                    "XX".to_owned()
8358                } else {
8359                    initials
8360                }),
8361            ),
8362        ]),
8363    )
8364}
8365
8366/// Renders service sort-order options through the shared select-option fragment.
8367///
8368/// # Parameters
8369///
8370/// - `app_root`: Input consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8371/// - `state_root`: Input consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8372/// - `business_id`: Input consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8373/// - `selected_order`: Input consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8374/// - `include_append`: Input consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8375///
8376/// # Returns
8377///
8378/// Returns [`Some`] when [`crate::runtime::json_commands::service_sort_order_options_html`] can produce a value and [`None`] otherwise.
8379///
8380/// # Performance
8381///
8382/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::service_sort_order_options_html`].
8383///
8384/// # Examples
8385///
8386/// ```rust,ignore
8387/// let _result = pharos_native::runtime::json_commands::service_sort_order_options_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
8388/// ```
8389///
8390/// # Related
8391///
8392/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8393pub fn service_sort_order_options_html(
8394    app_root: &Path,
8395    state_root: &Value,
8396    business_id: i64,
8397    selected_order: i64,
8398    include_append: bool,
8399) -> Option<String> {
8400    let count = state_rows(state_root, "services")
8401        .iter()
8402        .filter(|row| {
8403            row.get("business_id")
8404                .map(value_to_text)
8405                .and_then(|value| value.parse::<i64>().ok())
8406                == Some(business_id)
8407                && row
8408                    .get("is_active")
8409                    .and_then(Value::as_bool)
8410                    .unwrap_or(true)
8411        })
8412        .count() as i64;
8413    let max_order = if include_append { count + 1 } else { count }.max(1);
8414    let selected = if selected_order > 0 && selected_order <= max_order {
8415        selected_order
8416    } else {
8417        max_order
8418    };
8419    let mut out = String::new();
8420    for order in 1..=max_order {
8421        out.push_str(&render_fragment_with_params(
8422            app_root,
8423            "templates/shared/fragments/select_option.html",
8424            serde_json::Map::from_iter([
8425                ("option_value".to_owned(), Value::String(order.to_string())),
8426                (
8427                    "selected_attr".to_owned(),
8428                    Value::String(if order == selected { " selected" } else { "" }.to_owned()),
8429                ),
8430                ("option_label".to_owned(), Value::String(order.to_string())),
8431            ]),
8432        )?);
8433    }
8434    Some(out)
8435}
8436
8437/// Renders the booking-option editor from one service state record.
8438///
8439/// # Parameters
8440///
8441/// - `app_root`: Input consumed by [`crate::runtime::json_commands::service_booking_options_editor_html`].
8442/// - `state_root`: Input consumed by [`crate::runtime::json_commands::service_booking_options_editor_html`].
8443/// - `service_id`: Input consumed by [`crate::runtime::json_commands::service_booking_options_editor_html`].
8444///
8445/// # Returns
8446///
8447/// Returns [`Some`] when [`crate::runtime::json_commands::service_booking_options_editor_html`] can produce a value and [`None`] otherwise.
8448///
8449/// # Performance
8450///
8451/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::service_booking_options_editor_html`].
8452///
8453/// # Examples
8454///
8455/// ```rust,ignore
8456/// let _result = pharos_native::runtime::json_commands::service_booking_options_editor_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
8457/// ```
8458///
8459/// # Related
8460///
8461/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8462pub fn service_booking_options_editor_html(
8463    app_root: &Path,
8464    state_root: &Value,
8465    service_id: i64,
8466) -> Option<String> {
8467    let options = state_row_by_id(state_root, "services", service_id)
8468        .and_then(|row| row.get("booking_options"))
8469        .and_then(Value::as_array)
8470        .cloned()
8471        .unwrap_or_default();
8472    let mut rows_html = String::new();
8473    for (index, option) in options.iter().enumerate() {
8474        rows_html.push_str(&render_fragment_with_params(
8475            app_root,
8476            "templates/businesses/fragments/service_booking_option_row.html",
8477            serde_json::Map::from_iter([
8478                (
8479                    "option_index".to_owned(),
8480                    Value::String((index + 1).to_string()),
8481                ),
8482                (
8483                    "label_value".to_owned(),
8484                    Value::String(option.get("label").map(value_to_text).unwrap_or_default()),
8485                ),
8486                (
8487                    "duration_value".to_owned(),
8488                    Value::String(
8489                        option
8490                            .get("duration_minutes")
8491                            .map(value_to_text)
8492                            .unwrap_or_else(|| "45".to_owned()),
8493                    ),
8494                ),
8495                (
8496                    "cost_value".to_owned(),
8497                    Value::String(option.get("cost").map(value_to_text).unwrap_or_default()),
8498                ),
8499            ]),
8500        )?);
8501    }
8502    render_fragment_with_params(
8503        app_root,
8504        "templates/businesses/fragments/service_booking_options_editor.html",
8505        serde_json::Map::from_iter([
8506            (
8507                "option_count".to_owned(),
8508                Value::String(options.len().to_string()),
8509            ),
8510            (
8511                "option_count_text".to_owned(),
8512                Value::String(options.len().to_string()),
8513            ),
8514            ("option_rows_html".to_owned(), Value::String(rows_html)),
8515        ]),
8516    )
8517}
8518
8519/// Renders technician assignment checkbox fragments for one business/service.
8520///
8521/// # Parameters
8522///
8523/// - `app_root`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8524/// - `state_root`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8525/// - `business_id`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8526/// - `service_id`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8527/// - `empty_message`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8528/// - `select_all`: Input consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8529///
8530/// # Returns
8531///
8532/// Returns [`Some`] when [`crate::runtime::json_commands::technician_checkboxes_html`] can produce a value and [`None`] otherwise.
8533///
8534/// # Performance
8535///
8536/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::technician_checkboxes_html`].
8537///
8538/// # Examples
8539///
8540/// ```rust,ignore
8541/// let _result = pharos_native::runtime::json_commands::technician_checkboxes_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
8542/// ```
8543///
8544/// # Related
8545///
8546/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8547pub fn technician_checkboxes_html(
8548    app_root: &Path,
8549    state_root: &Value,
8550    business_id: i64,
8551    service_id: i64,
8552    empty_message: &str,
8553    select_all: bool,
8554) -> Option<String> {
8555    let assigned = state_row_by_id(state_root, "services", service_id)
8556        .and_then(|row| row.get("technician_ids"))
8557        .and_then(Value::as_array)
8558        .cloned()
8559        .unwrap_or_default();
8560    let mut out = String::new();
8561    for technician in state_rows(state_root, "technicians").iter().filter(|row| {
8562        row.get("business_id")
8563            .map(value_to_text)
8564            .and_then(|value| value.parse::<i64>().ok())
8565            == Some(business_id)
8566            && row.get("is_active").and_then(Value::as_bool) != Some(false)
8567    }) {
8568        let id = technician.get("id").map(value_to_text).unwrap_or_default();
8569        let checked = select_all || assigned.iter().map(value_to_text).any(|value| value == id);
8570        let technician_name = technician
8571            .get("name")
8572            .map(value_to_text)
8573            .unwrap_or_default();
8574        let label_html = render_fragment_with_params(
8575            app_root,
8576            "templates/shared/fragments/ui_label_technician_assignment.html",
8577            serde_json::Map::from_iter([(
8578                "technician_name".to_owned(),
8579                Value::String(technician_name.clone()),
8580            )]),
8581        )?;
8582        let technician_assignment_checkbox_ui_html = render_fragment_with_params(
8583            app_root,
8584            "templates/shared/fragments/ui_checkbox.html",
8585            serde_json::Map::from_iter([
8586                ("id".to_owned(), Value::String(format!("technician-{id}"))),
8587                ("name".to_owned(), Value::String(format!("technician_{id}"))),
8588                ("class_name".to_owned(), Value::String(String::new())),
8589                ("value".to_owned(), Value::String(id)),
8590                ("label_class".to_owned(), Value::String(String::new())),
8591                (
8592                    "attributes_html".to_owned(),
8593                    Value::String(if checked { " checked" } else { "" }.to_owned()),
8594                ),
8595                ("label_html".to_owned(), Value::String(label_html)),
8596                ("help_html".to_owned(), Value::String(String::new())),
8597            ]),
8598        )?;
8599        out.push_str(&render_fragment_with_params(
8600            app_root,
8601            "templates/businesses/fragments/technician_checkbox.html",
8602            serde_json::Map::from_iter([(
8603                "technician_assignment_checkbox_ui_html".to_owned(),
8604                Value::String(technician_assignment_checkbox_ui_html),
8605            )]),
8606        )?);
8607    }
8608    if out.is_empty() {
8609        render_fragment_with_params(
8610            app_root,
8611            "templates/shared/fragments/muted_text.html",
8612            serde_json::Map::from_iter([(
8613                "message".to_owned(),
8614                Value::String(empty_message.to_owned()),
8615            )]),
8616        )
8617    } else {
8618        Some(out)
8619    }
8620}
8621
8622/// Builds the generated-admin edit-page JSON contract for one existing item.
8623///
8624/// # Parameters
8625///
8626/// - `app_root`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8627/// - `state_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8628/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8629/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8630/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8631/// - `item_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8632///
8633/// # Returns
8634///
8635/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_edit_page_json`] can produce a value and [`None`] otherwise.
8636///
8637/// # Performance
8638///
8639/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_edit_page_json`].
8640///
8641/// # Examples
8642///
8643/// ```rust,ignore
8644/// let _result = pharos_native::runtime::json_commands::generated_surface_edit_page_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), "{}");
8645/// ```
8646///
8647/// # Related
8648///
8649/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8650pub fn generated_surface_edit_page_json(
8651    app_root: &Path,
8652    state_path: &Path,
8653    fixture_path: &Path,
8654    surface_json: &str,
8655    context_json: &str,
8656    item_json: &str,
8657) -> Option<String> {
8658    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
8659    let context = serde_json::from_str::<Value>(context_json).ok()?;
8660    let item = serde_json::from_str::<Value>(item_json).ok()?;
8661    let identity_field = surface
8662        .get("identity_field")
8663        .and_then(Value::as_str)
8664        .unwrap_or("id");
8665    let identity = item
8666        .get(identity_field)
8667        .map(value_to_text)
8668        .unwrap_or_default();
8669    let context_value = surface
8670        .get("context_binding")
8671        .and_then(|value| value.get("param"))
8672        .and_then(Value::as_str)
8673        .and_then(|param| context.get(param))
8674        .map(value_to_text);
8675    let form_fields = generated_surface_form_fields_html(
8676        app_root,
8677        state_path,
8678        fixture_path,
8679        surface_json,
8680        context_json,
8681        Some(item_json),
8682    )?;
8683    let title_field = surface
8684        .get("admin")
8685        .and_then(|value| value.get("item_title_field"))
8686        .and_then(Value::as_str)
8687        .unwrap_or("name");
8688    let title_value = generated_surface_display_value(item_json, title_field)
8689        .unwrap_or_else(|| format!("Record {identity}"));
8690    serde_json::to_string(&serde_json::json!({
8691        "title": format!("Edit {title_value}"),
8692        "manage_path": generated::runtime_generated_surface_operation_path(&surface, context_value.as_deref(), "manage", None).unwrap_or_default(),
8693        "update_path": generated::runtime_generated_surface_operation_path(&surface, context_value.as_deref(), "update", Some(&identity)).unwrap_or_default(),
8694        "form_fields_html": form_fields,
8695        "save_button_label": surface.get("admin").and_then(|value| value.get("save_button_label")).and_then(Value::as_str).unwrap_or("Save"),
8696        "delete_form_html": "",
8697    })).ok()
8698}
8699
8700const MAX_TEXT_BYTES: usize = 2 * 1024 * 1024;
8701const MAX_STATE_ROWS_JSON: usize = 16 * 1024;
8702const MAX_OUTPUT_ROWS_JSON: usize = 4096;
8703
8704/// Performs compact.
8705fn compact(value: &Value) -> Option<String> {
8706    let text = serde_json::to_string(value).ok()?;
8707    (text.len() <= MAX_TEXT_BYTES).then_some(text)
8708}
8709
8710/// Returns compact JSON text for a JSON value.
8711///
8712/// # Parameters
8713///
8714/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_compact_json_value`].
8715///
8716/// # Returns
8717///
8718/// Returns [`Some`] when [`crate::runtime::json_commands::emit_compact_json_value`] can produce a value and [`None`] otherwise.
8719///
8720/// # Examples
8721///
8722/// ```rust,ignore
8723/// let _result = pharos_native::runtime::json_commands::emit_compact_json_value("value");
8724/// ```
8725///
8726/// # Related
8727///
8728/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8729pub fn emit_compact_json_value(value: &Value) -> Option<String> {
8730    compact(value)
8731}
8732
8733/// Returns compact JSON text or an empty object for invalid input.
8734///
8735/// # Parameters
8736///
8737/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_json_text`].
8738///
8739/// # Returns
8740///
8741/// Returns the computed value produced by [`crate::runtime::json_commands::emit_json_text`].
8742///
8743/// # Examples
8744///
8745/// ```rust,ignore
8746/// let _result = pharos_native::runtime::json_commands::emit_json_text("value");
8747/// ```
8748///
8749/// # Related
8750///
8751/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8752pub fn emit_json_text(value: &Value) -> String {
8753    compact(value).unwrap_or_else(|| "{}".to_owned())
8754}
8755
8756/// Returns compact JSON text or an empty object for invalid serialized input.
8757///
8758/// # Parameters
8759///
8760/// - `text`: Input consumed by [`crate::runtime::json_commands::emit_json_or_empty`].
8761///
8762/// # Returns
8763///
8764/// Returns the computed value produced by [`crate::runtime::json_commands::emit_json_or_empty`].
8765///
8766/// # Performance
8767///
8768/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_json_or_empty`].
8769///
8770/// # Examples
8771///
8772/// ```rust,ignore
8773/// let _result = pharos_native::runtime::json_commands::emit_json_or_empty("{}");
8774/// ```
8775///
8776/// # Related
8777///
8778/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8779pub fn emit_json_or_empty(text: &str) -> String {
8780    serde_json::from_str::<Value>(text)
8781        .ok()
8782        .and_then(|value| compact(&value))
8783        .unwrap_or_else(|| "{}".to_owned())
8784}
8785
8786/// Serializes one string as a JSON string.
8787///
8788/// # Parameters
8789///
8790/// - `text`: Input consumed by [`crate::runtime::json_commands::emit_json_string`].
8791///
8792/// # Returns
8793///
8794/// Returns [`Some`] when [`crate::runtime::json_commands::emit_json_string`] can produce a value and [`None`] otherwise.
8795///
8796/// # Examples
8797///
8798/// ```rust,ignore
8799/// let _result = pharos_native::runtime::json_commands::emit_json_string("{}");
8800/// ```
8801///
8802/// # Related
8803///
8804/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8805pub fn emit_json_string(text: &str) -> Option<String> {
8806    compact(&Value::String(text.to_owned()))
8807}
8808
8809/// Serializes one signed integer as JSON text.
8810///
8811/// # Parameters
8812///
8813/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_long`].
8814///
8815/// # Returns
8816///
8817/// Returns the computed value produced by [`crate::runtime::json_commands::emit_long`].
8818///
8819/// # Examples
8820///
8821/// ```rust,ignore
8822/// let _result = pharos_native::runtime::json_commands::emit_long("value");
8823/// ```
8824///
8825/// # Related
8826///
8827/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8828pub fn emit_long(value: i64) -> String {
8829    value.to_string()
8830}
8831
8832/// Serializes a boolean as the native numeric flag representation.
8833///
8834/// # Parameters
8835///
8836/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_digit_bool`].
8837///
8838/// # Returns
8839///
8840/// Returns the computed value produced by [`crate::runtime::json_commands::emit_digit_bool`].
8841///
8842/// # Examples
8843///
8844/// ```rust,ignore
8845/// let _result = pharos_native::runtime::json_commands::emit_digit_bool("value");
8846/// ```
8847///
8848/// # Related
8849///
8850/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8851pub fn emit_digit_bool(value: bool) -> &'static str {
8852    if value { "1" } else { "0" }
8853}
8854
8855/// Returns a bounded line with a trailing newline.
8856///
8857/// # Parameters
8858///
8859/// - `text`: Input consumed by [`crate::runtime::json_commands::emit_text_line`].
8860///
8861/// # Returns
8862///
8863/// Returns [`Some`] when [`crate::runtime::json_commands::emit_text_line`] can produce a value and [`None`] otherwise.
8864///
8865/// # Performance
8866///
8867/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_text_line`].
8868///
8869/// # Examples
8870///
8871/// ```rust,ignore
8872/// let _result = pharos_native::runtime::json_commands::emit_text_line("{}");
8873/// ```
8874///
8875/// # Related
8876///
8877/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8878pub fn emit_text_line(text: &str) -> Option<String> {
8879    if text.len() >= MAX_TEXT_BYTES || text.chars().any(char::is_control) {
8880        return None;
8881    }
8882    Some(format!("{text}\n"))
8883}
8884
8885/// Adds a nullable string field to an object.
8886///
8887/// # Parameters
8888///
8889/// - `object`: Input consumed by [`crate::runtime::json_commands::add_json_string_or_null`].
8890/// - `key`: Input consumed by [`crate::runtime::json_commands::add_json_string_or_null`].
8891/// - `value`: Input consumed by [`crate::runtime::json_commands::add_json_string_or_null`].
8892///
8893/// # Returns
8894///
8895/// Returns `true` when the condition checked by [`crate::runtime::json_commands::add_json_string_or_null`] holds and `false` otherwise.
8896///
8897/// # Examples
8898///
8899/// ```rust,ignore
8900/// let _result = pharos_native::runtime::json_commands::add_json_string_or_null(todo!(), "key", "value");
8901/// ```
8902///
8903/// # Related
8904///
8905/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8906pub fn add_json_string_or_null(
8907    object: &mut Map<String, Value>,
8908    key: &str,
8909    value: Option<&str>,
8910) -> bool {
8911    if key.is_empty() {
8912        return false;
8913    }
8914    object.insert(
8915        key.to_owned(),
8916        value.map_or(Value::Null, |text| Value::String(text.to_owned())),
8917    );
8918    true
8919}
8920
8921/// Returns an optional string field from JSON text.
8922///
8923/// # Parameters
8924///
8925/// - `text`: Input consumed by [`crate::runtime::json_commands::json_option_value`].
8926/// - `key`: Input consumed by [`crate::runtime::json_commands::json_option_value`].
8927///
8928/// # Returns
8929///
8930/// Returns [`Some`] when [`crate::runtime::json_commands::json_option_value`] can produce a value and [`None`] otherwise.
8931///
8932/// # Performance
8933///
8934/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_option_value`].
8935///
8936/// # Examples
8937///
8938/// ```rust,ignore
8939/// let _result = pharos_native::runtime::json_commands::json_option_value("{}", "key");
8940/// ```
8941///
8942/// # Related
8943///
8944/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8945pub fn json_option_value(text: &str, key: &str) -> Option<String> {
8946    if key.is_empty() {
8947        return None;
8948    }
8949    serde_json::from_str::<Value>(text)
8950        .ok()?
8951        .get(key)
8952        .and_then(Value::as_str)
8953        .map(ToOwned::to_owned)
8954}
8955
8956/// Compares one JSON field with exact text.
8957///
8958/// # Parameters
8959///
8960/// - `text`: Input consumed by [`crate::runtime::json_commands::json_value_equals`].
8961/// - `key`: Input consumed by [`crate::runtime::json_commands::json_value_equals`].
8962/// - `expected`: Input consumed by [`crate::runtime::json_commands::json_value_equals`].
8963///
8964/// # Returns
8965///
8966/// Returns `true` when the condition checked by [`crate::runtime::json_commands::json_value_equals`] holds and `false` otherwise.
8967///
8968/// # Examples
8969///
8970/// ```rust,ignore
8971/// let _result = pharos_native::runtime::json_commands::json_value_equals("{}", "key", "value");
8972/// ```
8973///
8974/// # Related
8975///
8976/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
8977pub fn json_value_equals(text: &str, key: &str, expected: &str) -> bool {
8978    json_option_value(text, key).as_deref() == Some(expected)
8979}
8980
8981/// Returns a JSON object field as text.
8982///
8983/// # Parameters
8984///
8985/// - `text`: Input consumed by [`crate::runtime::json_commands::emit_object_string_field`].
8986/// - `key`: Input consumed by [`crate::runtime::json_commands::emit_object_string_field`].
8987///
8988/// # Returns
8989///
8990/// Returns [`Some`] when [`crate::runtime::json_commands::emit_object_string_field`] can produce a value and [`None`] otherwise.
8991///
8992/// # Examples
8993///
8994/// ```rust,ignore
8995/// let _result = pharos_native::runtime::json_commands::emit_object_string_field("{}", "key");
8996/// ```
8997///
8998/// # Related
8999///
9000/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9001pub fn emit_object_string_field(text: &str, key: &str) -> Option<String> {
9002    json_option_value(text, key)
9003}
9004
9005/// Returns a JSON value at a dotted object path.
9006///
9007/// # Parameters
9008///
9009/// - `text`: Input consumed by [`crate::runtime::json_commands::object_value_at_path`].
9010/// - `path`: Input consumed by [`crate::runtime::json_commands::object_value_at_path`].
9011///
9012/// # Returns
9013///
9014/// Returns [`Some`] when [`crate::runtime::json_commands::object_value_at_path`] can produce a value and [`None`] otherwise.
9015///
9016/// # Performance
9017///
9018/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::object_value_at_path`].
9019///
9020/// # Examples
9021///
9022/// ```rust,ignore
9023/// let _result = pharos_native::runtime::json_commands::object_value_at_path("{}", std::path::Path::new("fixture.json"));
9024/// ```
9025///
9026/// # Related
9027///
9028/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9029pub fn object_value_at_path(text: &str, path: &str) -> Option<String> {
9030    if path.is_empty() {
9031        return None;
9032    }
9033    let mut value = serde_json::from_str::<Value>(text).ok()?;
9034    for segment in path.split('.') {
9035        if segment.is_empty() {
9036            return None;
9037        }
9038        value = value.get(segment)?.clone();
9039    }
9040    compact(&value)
9041}
9042
9043/// Finds an array item by a string field.
9044///
9045/// # Parameters
9046///
9047/// - `text`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_string_field`].
9048/// - `section`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_string_field`].
9049/// - `field`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_string_field`].
9050/// - `expected`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_string_field`].
9051///
9052/// # Returns
9053///
9054/// Returns [`Some`] when [`crate::runtime::json_commands::find_array_item_by_string_field`] can produce a value and [`None`] otherwise.
9055///
9056/// # Performance
9057///
9058/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_array_item_by_string_field`].
9059///
9060/// # Examples
9061///
9062/// ```rust,ignore
9063/// let _result = pharos_native::runtime::json_commands::find_array_item_by_string_field("{}", "items", "field", "value");
9064/// ```
9065///
9066/// # Related
9067///
9068/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9069pub fn find_array_item_by_string_field(
9070    text: &str,
9071    section: &str,
9072    field: &str,
9073    expected: &str,
9074) -> Option<String> {
9075    let root = serde_json::from_str::<Value>(text).ok()?;
9076    root.get(section)
9077        .and_then(Value::as_array)?
9078        .iter()
9079        .find(|item| item.get(field).and_then(Value::as_str) == Some(expected))
9080        .and_then(compact)
9081}
9082
9083/// Finds a state user by numeric id.
9084///
9085/// # Parameters
9086///
9087/// - `text`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_id`].
9088/// - `user_id`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_id`].
9089///
9090/// # Returns
9091///
9092/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_user_by_id`] can produce a value and [`None`] otherwise.
9093///
9094/// # Performance
9095///
9096/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_find_user_by_id`].
9097///
9098/// # Examples
9099///
9100/// ```rust,ignore
9101/// let _result = pharos_native::runtime::json_commands::state_find_user_by_id("{}", 1);
9102/// ```
9103///
9104/// # Related
9105///
9106/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9107pub fn state_find_user_by_id(text: &str, user_id: i64) -> Option<String> {
9108    let root = serde_json::from_str::<Value>(text).ok()?;
9109    root.get("users")
9110        .and_then(Value::as_array)?
9111        .iter()
9112        .find(|row| row.get("id").and_then(Value::as_i64) == Some(user_id))
9113        .and_then(compact)
9114}
9115
9116/// Finds an appointment by numeric id.
9117///
9118/// # Parameters
9119///
9120/// - `text`: Input consumed by [`crate::runtime::json_commands::state_find_appointment_by_id`].
9121/// - `appointment_id`: Input consumed by [`crate::runtime::json_commands::state_find_appointment_by_id`].
9122///
9123/// # Returns
9124///
9125/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_appointment_by_id`] can produce a value and [`None`] otherwise.
9126///
9127/// # Performance
9128///
9129/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_find_appointment_by_id`].
9130///
9131/// # Examples
9132///
9133/// ```rust,ignore
9134/// let _result = pharos_native::runtime::json_commands::state_find_appointment_by_id("{}", 1);
9135/// ```
9136///
9137/// # Related
9138///
9139/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9140pub fn state_find_appointment_by_id(text: &str, appointment_id: i64) -> Option<String> {
9141    let root = serde_json::from_str::<Value>(text).ok()?;
9142    root.get("appointments")
9143        .and_then(Value::as_array)?
9144        .iter()
9145        .find(|row| row.get("id").and_then(Value::as_i64) == Some(appointment_id))
9146        .and_then(compact)
9147}
9148
9149/// Finds a user by case-insensitive email.
9150///
9151/// # Parameters
9152///
9153/// - `text`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_email`].
9154/// - `email`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_email`].
9155///
9156/// # Returns
9157///
9158/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_user_by_email`] can produce a value and [`None`] otherwise.
9159///
9160/// # Performance
9161///
9162/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_find_user_by_email`].
9163///
9164/// # Examples
9165///
9166/// ```rust,ignore
9167/// let _result = pharos_native::runtime::json_commands::state_find_user_by_email("{}", todo!());
9168/// ```
9169///
9170/// # Related
9171///
9172/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9173pub fn state_find_user_by_email(text: &str, email: &str) -> Option<String> {
9174    let root = serde_json::from_str::<Value>(text).ok()?;
9175    root.get("users")
9176        .and_then(Value::as_array)?
9177        .iter()
9178        .find(|row| {
9179            row.get("email")
9180                .and_then(Value::as_str)
9181                .is_some_and(|value| value.eq_ignore_ascii_case(email))
9182        })
9183        .and_then(compact)
9184}
9185
9186/// Finds a user by exact username.
9187///
9188/// # Parameters
9189///
9190/// - `text`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_username`].
9191/// - `username`: Input consumed by [`crate::runtime::json_commands::state_find_user_by_username`].
9192///
9193/// # Returns
9194///
9195/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_user_by_username`] can produce a value and [`None`] otherwise.
9196///
9197/// # Examples
9198///
9199/// ```rust,ignore
9200/// let _result = pharos_native::runtime::json_commands::state_find_user_by_username("{}", todo!());
9201/// ```
9202///
9203/// # Related
9204///
9205/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9206pub fn state_find_user_by_username(text: &str, username: &str) -> Option<String> {
9207    find_array_item_by_string_field(text, "users", "username", username)
9208}
9209
9210/// Adds an array field to an object if it is absent.
9211///
9212/// # Parameters
9213///
9214/// - `root`: Input consumed by [`crate::runtime::json_commands::ensure_mut_array_field`].
9215/// - `key`: Input consumed by [`crate::runtime::json_commands::ensure_mut_array_field`].
9216///
9217/// # Returns
9218///
9219/// Returns `true` when the condition checked by [`crate::runtime::json_commands::ensure_mut_array_field`] holds and `false` otherwise.
9220///
9221/// # Examples
9222///
9223/// ```rust,ignore
9224/// let _result = pharos_native::runtime::json_commands::ensure_mut_array_field(std::path::Path::new("."), "key");
9225/// ```
9226///
9227/// # Related
9228///
9229/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9230pub fn ensure_mut_array_field(root: &mut Map<String, Value>, key: &str) -> bool {
9231    if key.is_empty() {
9232        return false;
9233    }
9234    root.entry(key.to_owned())
9235        .or_insert_with(|| Value::Array(Vec::new()))
9236        .is_array()
9237}
9238
9239/// Finds a multipart text field using the existing bounded multipart parser.
9240///
9241/// # Parameters
9242///
9243/// - `content_type`: Input consumed by [`crate::runtime::json_commands::multipart_find_part`].
9244/// - `body_path`: Input consumed by [`crate::runtime::json_commands::multipart_find_part`].
9245/// - `field_name`: Input consumed by [`crate::runtime::json_commands::multipart_find_part`].
9246///
9247/// # Returns
9248///
9249/// Returns [`Some`] when [`crate::runtime::json_commands::multipart_find_part`] can produce a value and [`None`] otherwise.
9250///
9251/// # Examples
9252///
9253/// ```rust,ignore
9254/// let _result = pharos_native::runtime::json_commands::multipart_find_part(todo!(), todo!(), todo!());
9255/// ```
9256///
9257/// # Related
9258///
9259/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9260pub fn multipart_find_part(
9261    content_type: &str,
9262    body_path: &Path,
9263    field_name: &str,
9264) -> Option<String> {
9265    dynamic_multipart_extract_text(content_type, body_path, field_name)
9266}
9267
9268/// Exports relational runtime state through the configured native adapter.
9269///
9270/// # Parameters
9271///
9272/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_export_json_runtime`].
9273/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_export_json_runtime`].
9274/// - `app_id`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_export_json_runtime`].
9275///
9276/// # Returns
9277///
9278/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_runtime_state_export_json_runtime`] can produce a value and [`None`] otherwise.
9279///
9280/// # Examples
9281///
9282/// ```rust,ignore
9283/// let _result = pharos_native::runtime::json_commands::dynamic_runtime_state_export_json_runtime(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
9284/// ```
9285///
9286/// # Related
9287///
9288/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9289pub fn dynamic_runtime_state_export_json_runtime(
9290    app_root: &Path,
9291    runtime_conf_path: Option<&Path>,
9292    app_id: Option<&str>,
9293) -> Option<String> {
9294    dynamic_relational_runtime_export_json(app_root, runtime_conf_path, app_id)
9295}
9296
9297/// Imports relational runtime state through the configured native adapter.
9298///
9299/// # Parameters
9300///
9301/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9302/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9303/// - `app_id`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9304/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9305/// - `expected_audit_count`: Input consumed by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9306///
9307/// # Returns
9308///
9309/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_runtime_state_import_json_runtime`].
9310///
9311/// # Examples
9312///
9313/// ```rust,ignore
9314/// let _result = pharos_native::runtime::json_commands::dynamic_runtime_state_import_json_runtime(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
9315/// ```
9316///
9317/// # Related
9318///
9319/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9320pub fn dynamic_runtime_state_import_json_runtime(
9321    app_root: &Path,
9322    runtime_conf_path: Option<&Path>,
9323    app_id: Option<&str>,
9324    state_path: &Path,
9325    expected_audit_count: Option<&str>,
9326) -> i32 {
9327    dynamic_relational_runtime_import_state(
9328        app_root,
9329        runtime_conf_path,
9330        app_id,
9331        state_path,
9332        expected_audit_count,
9333    )
9334}
9335
9336/// Dispatches a named JSON command against a persisted state file.
9337///
9338/// # Parameters
9339///
9340/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dispatch_json_command_entries`].
9341/// - `command`: Input consumed by [`crate::runtime::json_commands::dispatch_json_command_entries`].
9342/// - `options_json`: Input consumed by [`crate::runtime::json_commands::dispatch_json_command_entries`].
9343///
9344/// # Returns
9345///
9346/// Returns the successful value produced by [`crate::runtime::json_commands::dispatch_json_command_entries`] or an error when the operation fails.
9347///
9348/// # Errors
9349///
9350/// Returns an error value when [`crate::runtime::json_commands::dispatch_json_command_entries`] cannot complete successfully.
9351///
9352/// # Examples
9353///
9354/// ```rust,ignore
9355/// let _result = pharos_native::runtime::json_commands::dispatch_json_command_entries(todo!(), todo!(), todo!());
9356/// ```
9357///
9358/// # Related
9359///
9360/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9361pub fn dispatch_json_command_entries(
9362    state_path: &Path,
9363    command: &str,
9364    options_json: &str,
9365) -> Result<String, i32> {
9366    state_named_command(state_path, command, options_json)
9367}
9368
9369/// Dispatches the native JSON command surface without a shell bridge.
9370///
9371/// # Parameters
9372///
9373/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_json_command`].
9374/// - `command`: Input consumed by [`crate::runtime::json_commands::handle_json_command`].
9375/// - `options_json`: Input consumed by [`crate::runtime::json_commands::handle_json_command`].
9376///
9377/// # Returns
9378///
9379/// Returns the successful value produced by [`crate::runtime::json_commands::handle_json_command`] or an error when the operation fails.
9380///
9381/// # Errors
9382///
9383/// Returns an error value when [`crate::runtime::json_commands::handle_json_command`] cannot complete successfully.
9384///
9385/// # Examples
9386///
9387/// ```rust,ignore
9388/// let _result = pharos_native::runtime::json_commands::handle_json_command(todo!(), todo!(), todo!());
9389/// ```
9390///
9391/// # Related
9392///
9393/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9394pub fn handle_json_command(
9395    state_path: &Path,
9396    command: &str,
9397    options_json: &str,
9398) -> Result<String, i32> {
9399    dispatch_json_command_entries(state_path, command, options_json)
9400}
9401
9402/// Returns generated-surface list-column metadata.
9403///
9404/// # Parameters
9405///
9406/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_list_columns_runtime`].
9407///
9408/// # Returns
9409///
9410/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_list_columns_runtime`] can produce a value and [`None`] otherwise.
9411///
9412/// # Examples
9413///
9414/// ```rust,ignore
9415/// let _result = pharos_native::runtime::json_commands::generated_surface_list_columns_runtime("{}");
9416/// ```
9417///
9418/// # Related
9419///
9420/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9421pub fn generated_surface_list_columns_runtime(surface_json: &str) -> Option<String> {
9422    generated_surface_list_columns(surface_json)
9423}
9424
9425/// Handles state named command.
9426///
9427/// # Parameters
9428///
9429/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_state_named_command`].
9430/// - `name`: Input consumed by [`crate::runtime::json_commands::handle_state_named_command`].
9431/// - `options_json`: Input consumed by [`crate::runtime::json_commands::handle_state_named_command`].
9432///
9433/// # Returns
9434///
9435/// Returns the successful value produced by [`crate::runtime::json_commands::handle_state_named_command`] or an error when the operation fails.
9436///
9437/// # Errors
9438///
9439/// Returns an error value when [`crate::runtime::json_commands::handle_state_named_command`] cannot complete successfully.
9440///
9441/// # Examples
9442///
9443/// ```rust,ignore
9444/// let _result = pharos_native::runtime::json_commands::handle_state_named_command(todo!(), "name", todo!());
9445/// ```
9446///
9447/// # Related
9448///
9449/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9450pub fn handle_state_named_command(
9451    state_path: &Path,
9452    name: &str,
9453    options_json: &str,
9454) -> Result<String, i32> {
9455    state_named_command(state_path, name, options_json)
9456}
9457
9458/// Handles file generated surface match command.
9459///
9460/// # Parameters
9461///
9462/// - `file_path`: Input consumed by [`crate::runtime::json_commands::handle_file_generated_surface_match_command`].
9463/// - `method`: Input consumed by [`crate::runtime::json_commands::handle_file_generated_surface_match_command`].
9464/// - `request_path`: Input consumed by [`crate::runtime::json_commands::handle_file_generated_surface_match_command`].
9465///
9466/// # Returns
9467///
9468/// Returns [`Some`] when [`crate::runtime::json_commands::handle_file_generated_surface_match_command`] can produce a value and [`None`] otherwise.
9469///
9470/// # Examples
9471///
9472/// ```rust,ignore
9473/// let _result = pharos_native::runtime::json_commands::handle_file_generated_surface_match_command(todo!(), todo!(), "/");
9474/// ```
9475///
9476/// # Related
9477///
9478/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9479pub fn handle_file_generated_surface_match_command(
9480    file_path: &Path,
9481    method: &str,
9482    request_path: &str,
9483) -> Option<String> {
9484    file_generated_surface_match(file_path, method, request_path)
9485}
9486
9487/// Handles generated surface list columns JSON command.
9488///
9489/// # Parameters
9490///
9491/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_list_columns_json_command`].
9492///
9493/// # Returns
9494///
9495/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_list_columns_json_command`] can produce a value and [`None`] otherwise.
9496///
9497/// # Examples
9498///
9499/// ```rust,ignore
9500/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_list_columns_json_command("{}");
9501/// ```
9502///
9503/// # Related
9504///
9505/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9506pub fn handle_generated_surface_list_columns_json_command(surface_json: &str) -> Option<String> {
9507    generated_surface_list_columns(surface_json)
9508}
9509
9510/// Returns generated-surface request parameters.
9511///
9512/// # Parameters
9513///
9514/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_params_runtime`].
9515/// - `context_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_params_runtime`].
9516/// - `identity_value`: Input consumed by [`crate::runtime::json_commands::generated_surface_params_runtime`].
9517///
9518/// # Returns
9519///
9520/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_params_runtime`] can produce a value and [`None`] otherwise.
9521///
9522/// # Examples
9523///
9524/// ```rust,ignore
9525/// let _result = pharos_native::runtime::json_commands::generated_surface_params_runtime("{}", todo!(), todo!());
9526/// ```
9527///
9528/// # Related
9529///
9530/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9531pub fn generated_surface_params_runtime(
9532    surface_json: &str,
9533    context_json: &str,
9534    identity_value: Option<&str>,
9535) -> Option<String> {
9536    generated_surface_params(surface_json, context_json, identity_value)
9537}
9538
9539/// Handles generated surface params JSON command.
9540///
9541/// # Parameters
9542///
9543/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_params_json_command`].
9544/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_params_json_command`].
9545/// - `identity_value`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_params_json_command`].
9546///
9547/// # Returns
9548///
9549/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_params_json_command`] can produce a value and [`None`] otherwise.
9550///
9551/// # Examples
9552///
9553/// ```rust,ignore
9554/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_params_json_command("{}", todo!(), todo!());
9555/// ```
9556///
9557/// # Related
9558///
9559/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9560pub fn handle_generated_surface_params_json_command(
9561    surface_json: &str,
9562    context_json: &str,
9563    identity_value: Option<&str>,
9564) -> Option<String> {
9565    generated_surface_params(surface_json, context_json, identity_value)
9566}
9567
9568/// Returns generated-surface display text for a field.
9569///
9570/// # Parameters
9571///
9572/// - `item_json`: Input consumed by [`crate::runtime::json_commands::generated_surface_display_value_runtime`].
9573/// - `field_name`: Input consumed by [`crate::runtime::json_commands::generated_surface_display_value_runtime`].
9574///
9575/// # Returns
9576///
9577/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_display_value_runtime`] can produce a value and [`None`] otherwise.
9578///
9579/// # Examples
9580///
9581/// ```rust,ignore
9582/// let _result = pharos_native::runtime::json_commands::generated_surface_display_value_runtime("{}", todo!());
9583/// ```
9584///
9585/// # Related
9586///
9587/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9588pub fn generated_surface_display_value_runtime(
9589    item_json: &str,
9590    field_name: &str,
9591) -> Option<String> {
9592    generated_surface_display_value(item_json, field_name)
9593}
9594
9595/// Handles generated surface display value command.
9596///
9597/// # Parameters
9598///
9599/// - `item_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_display_value_command`].
9600/// - `field_name`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_display_value_command`].
9601///
9602/// # Returns
9603///
9604/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_display_value_command`] can produce a value and [`None`] otherwise.
9605///
9606/// # Examples
9607///
9608/// ```rust,ignore
9609/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_display_value_command("{}", todo!());
9610/// ```
9611///
9612/// # Related
9613///
9614/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9615pub fn handle_generated_surface_display_value_command(
9616    item_json: &str,
9617    field_name: &str,
9618) -> Option<String> {
9619    generated_surface_display_value(item_json, field_name)
9620}
9621
9622/// Handles generated surface select options HTML command.
9623///
9624/// # Parameters
9625///
9626/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_select_options_html_command`].
9627/// - `field_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_select_options_html_command`].
9628/// - `selected_value`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_select_options_html_command`].
9629///
9630/// # Returns
9631///
9632/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_select_options_html_command`] can produce a value and [`None`] otherwise.
9633///
9634/// # Examples
9635///
9636/// ```rust,ignore
9637/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_select_options_html_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
9638/// ```
9639///
9640/// # Related
9641///
9642/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9643pub fn handle_generated_surface_select_options_html_command(
9644    app_root: &Path,
9645    field_json: &str,
9646    selected_value: Option<&str>,
9647) -> Option<String> {
9648    generated_surface_select_options_html(app_root, field_json, selected_value)
9649}
9650
9651/// Handles generated surface relation checkboxes HTML command.
9652///
9653/// # Parameters
9654///
9655/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`].
9656/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`].
9657/// - `relation_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`].
9658/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`].
9659/// - `selected_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`].
9660///
9661/// # Returns
9662///
9663/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command`] can produce a value and [`None`] otherwise.
9664///
9665/// # Examples
9666///
9667/// ```rust,ignore
9668/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_relation_checkboxes_html_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
9669/// ```
9670///
9671/// # Related
9672///
9673/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9674pub fn handle_generated_surface_relation_checkboxes_html_command(
9675    app_root: &Path,
9676    state_path: &Path,
9677    relation_json: &str,
9678    context_json: &str,
9679    selected_json: Option<&str>,
9680) -> Option<String> {
9681    generated_surface_relation_checkboxes_html(
9682        app_root,
9683        state_path,
9684        relation_json,
9685        context_json,
9686        selected_json,
9687    )
9688}
9689
9690/// Handles generated surface manage table JSON command.
9691///
9692/// # Parameters
9693///
9694/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_table_json_command`].
9695/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_table_json_command`].
9696/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_table_json_command`].
9697/// - `list_result_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_table_json_command`].
9698///
9699/// # Returns
9700///
9701/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_manage_table_json_command`] can produce a value and [`None`] otherwise.
9702///
9703/// # Examples
9704///
9705/// ```rust,ignore
9706/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_manage_table_json_command(std::path::Path::new("apps/dev_docs"), "{}", todo!(), todo!());
9707/// ```
9708///
9709/// # Related
9710///
9711/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9712pub fn handle_generated_surface_manage_table_json_command(
9713    app_root: &Path,
9714    surface_json: &str,
9715    context_json: &str,
9716    list_result_json: &str,
9717) -> Option<String> {
9718    generated_surface_manage_table_json(app_root, surface_json, context_json, list_result_json)
9719}
9720
9721/// Handles generated surface form fields HTML command.
9722///
9723/// # Parameters
9724///
9725/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9726/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9727/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9728/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9729/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9730/// - `item_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`].
9731///
9732/// # Returns
9733///
9734/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_form_fields_html_command`] can produce a value and [`None`] otherwise.
9735///
9736/// # Examples
9737///
9738/// ```rust,ignore
9739/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_form_fields_html_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), "{}");
9740/// ```
9741///
9742/// # Related
9743///
9744/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9745pub fn handle_generated_surface_form_fields_html_command(
9746    app_root: &Path,
9747    state_path: &Path,
9748    fixture_path: &Path,
9749    surface_json: &str,
9750    context_json: &str,
9751    item_json: Option<&str>,
9752) -> Option<String> {
9753    generated_surface_form_fields_html(
9754        app_root,
9755        state_path,
9756        fixture_path,
9757        surface_json,
9758        context_json,
9759        item_json,
9760    )
9761}
9762
9763/// Handles generated surface filter controls HTML command.
9764///
9765/// # Parameters
9766///
9767/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_filter_controls_html_command`].
9768/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_filter_controls_html_command`].
9769/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_filter_controls_html_command`].
9770///
9771/// # Returns
9772///
9773/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_filter_controls_html_command`] can produce a value and [`None`] otherwise.
9774///
9775/// # Examples
9776///
9777/// ```rust,ignore
9778/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_filter_controls_html_command(std::path::Path::new("apps/dev_docs"), "{}", todo!());
9779/// ```
9780///
9781/// # Related
9782///
9783/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9784pub fn handle_generated_surface_filter_controls_html_command(
9785    app_root: &Path,
9786    surface_json: &str,
9787    raw_query: &str,
9788) -> Option<String> {
9789    generated_surface_filter_controls_html(app_root, surface_json, raw_query)
9790}
9791
9792/// Handles generated surface sort options HTML command.
9793///
9794/// # Parameters
9795///
9796/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_sort_options_html_command`].
9797/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_sort_options_html_command`].
9798/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_sort_options_html_command`].
9799///
9800/// # Returns
9801///
9802/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_sort_options_html_command`] can produce a value and [`None`] otherwise.
9803///
9804/// # Examples
9805///
9806/// ```rust,ignore
9807/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_sort_options_html_command(std::path::Path::new("apps/dev_docs"), "{}", todo!());
9808/// ```
9809///
9810/// # Related
9811///
9812/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9813pub fn handle_generated_surface_sort_options_html_command(
9814    app_root: &Path,
9815    surface_json: &str,
9816    raw_query: &str,
9817) -> Option<String> {
9818    generated_surface_sort_options_html(app_root, surface_json, raw_query)
9819}
9820
9821/// Handles generated surface context command.
9822///
9823/// # Parameters
9824///
9825/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_context_command`].
9826/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_context_command`].
9827/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_context_command`].
9828///
9829/// # Returns
9830///
9831/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_context_command`] can produce a value and [`None`] otherwise.
9832///
9833/// # Examples
9834///
9835/// ```rust,ignore
9836/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_context_command(todo!(), "{}", todo!());
9837/// ```
9838///
9839/// # Related
9840///
9841/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9842pub fn handle_generated_surface_context_command(
9843    state_path: &Path,
9844    surface_json: &str,
9845    params_json: &str,
9846) -> Option<String> {
9847    generated_surface_context_json(state_path, surface_json, params_json)
9848}
9849
9850/// Handles generated surface submitted command.
9851///
9852/// # Parameters
9853///
9854/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_submitted_command`].
9855/// - `request_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_submitted_command`].
9856///
9857/// # Returns
9858///
9859/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_submitted_command`] can produce a value and [`None`] otherwise.
9860///
9861/// # Performance
9862///
9863/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_generated_surface_submitted_command`].
9864///
9865/// # Examples
9866///
9867/// ```rust,ignore
9868/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_submitted_command("{}", todo!());
9869/// ```
9870///
9871/// # Related
9872///
9873/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9874pub fn handle_generated_surface_submitted_command(
9875    surface_json: &str,
9876    request_json: &str,
9877) -> Option<String> {
9878    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
9879    let payload = serde_json::from_str::<Value>(request_json).ok()?;
9880    let form_root = serde_json::json!({
9881        "forms": [{
9882            "form_id": surface.get("form_id").and_then(Value::as_str).unwrap_or_default(),
9883            "fields": surface
9884                .get("fields")
9885                .and_then(Value::as_array)
9886                .cloned()
9887                .unwrap_or_default()
9888        }]
9889    });
9890    generated::generated_surface_submitted_json(&surface, &form_root, &payload)
9891        .or_else(|| compact(&payload))
9892}
9893
9894/// Handles generated surface list result command.
9895///
9896/// # Parameters
9897///
9898/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_list_result_command`].
9899/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_list_result_command`].
9900/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_list_result_command`].
9901/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_list_result_command`].
9902///
9903/// # Returns
9904///
9905/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_list_result_command`] can produce a value and [`None`] otherwise.
9906///
9907/// # Examples
9908///
9909/// ```rust,ignore
9910/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_list_result_command(todo!(), "{}", todo!(), todo!());
9911/// ```
9912///
9913/// # Related
9914///
9915/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9916pub fn handle_generated_surface_list_result_command(
9917    state_path: &Path,
9918    surface_json: &str,
9919    context_json: &str,
9920    raw_query: &str,
9921) -> Option<String> {
9922    generated_surface_list_result_json(state_path, surface_json, context_json, raw_query)
9923}
9924
9925/// Handles generated surface default candidate command.
9926///
9927/// # Parameters
9928///
9929/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`].
9930/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`].
9931/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`].
9932/// - `existing_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`].
9933/// - `submitted_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`].
9934///
9935/// # Returns
9936///
9937/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_default_candidate_command`] can produce a value and [`None`] otherwise.
9938///
9939/// # Examples
9940///
9941/// ```rust,ignore
9942/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_default_candidate_command(todo!(), "{}", todo!(), todo!(), todo!());
9943/// ```
9944///
9945/// # Related
9946///
9947/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9948pub fn handle_generated_surface_default_candidate_command(
9949    state_path: &Path,
9950    surface_json: &str,
9951    context_json: &str,
9952    existing_json: Option<&str>,
9953    submitted_json: Option<&str>,
9954) -> Option<String> {
9955    generated_surface_default_candidate_json(
9956        state_path,
9957        surface_json,
9958        context_json,
9959        existing_json,
9960        submitted_json,
9961    )
9962}
9963
9964/// Handles generated surface validation report command.
9965///
9966/// # Parameters
9967///
9968/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`].
9969/// - `action_id`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`].
9970/// - `actor_scope`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`].
9971/// - `tenant_scope`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`].
9972///
9973/// # Returns
9974///
9975/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`] can produce a value and [`None`] otherwise.
9976///
9977/// # Performance
9978///
9979/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_generated_surface_validation_report_command`].
9980///
9981/// # Examples
9982///
9983/// ```rust,ignore
9984/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_validation_report_command("{}", todo!(), todo!(), todo!());
9985/// ```
9986///
9987/// # Related
9988///
9989/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
9990pub fn handle_generated_surface_validation_report_command(
9991    surface_json: &str,
9992    action_id: Option<&str>,
9993    actor_scope: Option<&str>,
9994    tenant_scope: Option<&str>,
9995) -> Option<String> {
9996    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
9997    generated::generated_surface_validation_report_empty(
9998        surface.get("form_id").and_then(Value::as_str),
9999        action_id,
10000        actor_scope,
10001        tenant_scope,
10002    )
10003}
10004
10005/// Handles generated surface mutate command.
10006///
10007/// # Parameters
10008///
10009/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_mutate_command`].
10010/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_mutate_command`].
10011/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_mutate_command`].
10012/// - `candidate_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_mutate_command`].
10013///
10014/// # Returns
10015///
10016/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_mutate_command`] can produce a value and [`None`] otherwise.
10017///
10018/// # Examples
10019///
10020/// ```rust,ignore
10021/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_mutate_command(todo!(), "{}", todo!(), todo!());
10022/// ```
10023///
10024/// # Related
10025///
10026/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10027pub fn handle_generated_surface_mutate_command(
10028    state_path: &Path,
10029    surface_json: &str,
10030    context_json: &str,
10031    candidate_json: &str,
10032) -> Option<String> {
10033    generated_surface_default_candidate_json(
10034        state_path,
10035        surface_json,
10036        context_json,
10037        None,
10038        Some(candidate_json),
10039    )
10040}
10041
10042/// Validates a generated-surface candidate through the existing typed helper.
10043///
10044/// # Parameters
10045///
10046/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_coerce_candidate_command`].
10047/// - `candidate_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_coerce_candidate_command`].
10048///
10049/// # Returns
10050///
10051/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_coerce_candidate_command`] can produce a value and [`None`] otherwise.
10052///
10053/// # Performance
10054///
10055/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_generated_surface_coerce_candidate_command`].
10056///
10057/// # Examples
10058///
10059/// ```rust,ignore
10060/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_coerce_candidate_command("{}", todo!());
10061/// ```
10062///
10063/// # Related
10064///
10065/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10066pub fn handle_generated_surface_coerce_candidate_command(
10067    surface_json: &str,
10068    candidate_json: &str,
10069) -> Option<String> {
10070    let surface_root = serde_json::from_str::<Value>(surface_json).ok()?;
10071    generated::generated_surface_coerce_candidate_json(&surface_root, candidate_json)
10072}
10073
10074/// Builds the generated-surface edit page JSON.
10075///
10076/// # Parameters
10077///
10078/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10079/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10080/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10081/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10082/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10083/// - `item_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`].
10084///
10085/// # Returns
10086///
10087/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_edit_page_json_command`] can produce a value and [`None`] otherwise.
10088///
10089/// # Examples
10090///
10091/// ```rust,ignore
10092/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_edit_page_json_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), "{}");
10093/// ```
10094///
10095/// # Related
10096///
10097/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10098pub fn handle_generated_surface_edit_page_json_command(
10099    app_root: &Path,
10100    state_path: &Path,
10101    fixture_path: &Path,
10102    surface_json: &str,
10103    context_json: &str,
10104    item_json: &str,
10105) -> Option<String> {
10106    generated_surface_edit_page_json(
10107        app_root,
10108        state_path,
10109        fixture_path,
10110        surface_json,
10111        context_json,
10112        item_json,
10113    )
10114}
10115
10116/// Builds the generated-surface management page JSON.
10117///
10118/// # Parameters
10119///
10120/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10121/// - `state_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10122/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10123/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10124/// - `context_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10125/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`].
10126///
10127/// # Returns
10128///
10129/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_manage_page_json_command`] can produce a value and [`None`] otherwise.
10130///
10131/// # Examples
10132///
10133/// ```rust,ignore
10134/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_manage_page_json_command(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), todo!());
10135/// ```
10136///
10137/// # Related
10138///
10139/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10140pub fn handle_generated_surface_manage_page_json_command(
10141    app_root: &Path,
10142    state_path: &Path,
10143    fixture_path: &Path,
10144    surface_json: &str,
10145    context_json: &str,
10146    raw_query: &str,
10147) -> Option<String> {
10148    generated_surface_manage_page_json(
10149        app_root,
10150        state_path,
10151        fixture_path,
10152        surface_json,
10153        context_json,
10154        raw_query,
10155    )
10156}
10157
10158/// Performs object from text.
10159fn object_from_text(text: &str) -> Option<Value> {
10160    let value = serde_json::from_str::<Value>(text).ok()?;
10161    value.is_object().then_some(value)
10162}
10163
10164/// Performs bounded state array.
10165fn bounded_state_array<'a>(root: &'a Value, section: &str) -> &'a [Value] {
10166    root.get(section)
10167        .and_then(Value::as_array)
10168        .map(|items| &items[..items.len().min(MAX_STATE_ROWS_JSON)])
10169        .unwrap_or(&[])
10170}
10171
10172/// Appends an audit event to a mutable generated-surface state document.
10173///
10174/// # Parameters
10175///
10176/// - `root`: Input consumed by [`crate::runtime::json_commands::generated_surface_append_audit_event_mut`].
10177/// - `event`: Input consumed by [`crate::runtime::json_commands::generated_surface_append_audit_event_mut`].
10178///
10179/// # Returns
10180///
10181/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_append_audit_event_mut`] holds and `false` otherwise.
10182///
10183/// # Examples
10184///
10185/// ```rust,ignore
10186/// let _result = pharos_native::runtime::json_commands::generated_surface_append_audit_event_mut(std::path::Path::new("."), todo!());
10187/// ```
10188///
10189/// # Related
10190///
10191/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10192pub fn generated_surface_append_audit_event_mut(root: &mut Value, event: Value) -> bool {
10193    let Some(object) = root.as_object_mut() else {
10194        return false;
10195    };
10196    if !event.is_object() {
10197        return false;
10198    }
10199    let events = object
10200        .entry("audit_events".to_owned())
10201        .or_insert_with(|| Value::Array(Vec::new()));
10202    let Some(items) = events.as_array_mut() else {
10203        return false;
10204    };
10205    if items.len() >= MAX_STATE_ROWS_JSON {
10206        return false;
10207    }
10208    items.push(event);
10209    true
10210}
10211
10212/// Tests whether an array contains an exact string value.
10213///
10214/// # Parameters
10215///
10216/// - `values`: Input consumed by [`crate::runtime::json_commands::generated_surface_array_contains_string`].
10217/// - `expected`: Input consumed by [`crate::runtime::json_commands::generated_surface_array_contains_string`].
10218///
10219/// # Returns
10220///
10221/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_array_contains_string`] holds and `false` otherwise.
10222///
10223/// # Performance
10224///
10225/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_array_contains_string`].
10226///
10227/// # Examples
10228///
10229/// ```rust,ignore
10230/// let _result = pharos_native::runtime::json_commands::generated_surface_array_contains_string(todo!(), "value");
10231/// ```
10232///
10233/// # Related
10234///
10235/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10236pub fn generated_surface_array_contains_string(values: &Value, expected: &str) -> bool {
10237    !expected.is_empty()
10238        && values
10239            .as_array()
10240            .is_some_and(|items| items.iter().any(|item| item.as_str() == Some(expected)))
10241}
10242
10243/// Normalizes generated-surface order values to stable positive integers.
10244///
10245/// # Parameters
10246///
10247/// - `values`: Input consumed by [`crate::runtime::json_commands::generated_surface_normalize_order_mut`].
10248/// - `field`: Input consumed by [`crate::runtime::json_commands::generated_surface_normalize_order_mut`].
10249///
10250/// # Returns
10251///
10252/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_normalize_order_mut`] holds and `false` otherwise.
10253///
10254/// # Performance
10255///
10256/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_normalize_order_mut`].
10257///
10258/// # Examples
10259///
10260/// ```rust,ignore
10261/// let _result = pharos_native::runtime::json_commands::generated_surface_normalize_order_mut(todo!(), "field");
10262/// ```
10263///
10264/// # Related
10265///
10266/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10267pub fn generated_surface_normalize_order_mut(values: &mut Value, field: &str) -> bool {
10268    if field.is_empty() {
10269        return false;
10270    }
10271    let Some(items) = values.as_array_mut() else {
10272        return false;
10273    };
10274    for (index, item) in items.iter_mut().enumerate() {
10275        let Some(object) = item.as_object_mut() else {
10276            return false;
10277        };
10278        let value = object
10279            .get(field)
10280            .and_then(Value::as_i64)
10281            .filter(|value| *value > 0)
10282            .unwrap_or(index as i64 + 1);
10283        object.insert(field.to_owned(), Value::from(value));
10284    }
10285    true
10286}
10287
10288/// Validates that every relation value is an integer identifier.
10289///
10290/// # Parameters
10291///
10292/// - `values`: Input consumed by [`crate::runtime::json_commands::generated_surface_relation_array_all_integers`].
10293///
10294/// # Returns
10295///
10296/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_relation_array_all_integers`] holds and `false` otherwise.
10297///
10298/// # Performance
10299///
10300/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_relation_array_all_integers`].
10301///
10302/// # Examples
10303///
10304/// ```rust,ignore
10305/// let _result = pharos_native::runtime::json_commands::generated_surface_relation_array_all_integers(todo!());
10306/// ```
10307///
10308/// # Related
10309///
10310/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10311pub fn generated_surface_relation_array_all_integers(values: &Value) -> bool {
10312    values.as_array().is_some_and(|items| {
10313        items
10314            .iter()
10315            .all(|item| item.as_i64().is_some() || item.as_u64().is_some())
10316    })
10317}
10318
10319/// Adds one field error to a mutable validation report.
10320///
10321/// # Parameters
10322///
10323/// - `report`: Input consumed by [`crate::runtime::json_commands::generated_surface_report_add_field_error`].
10324/// - `field`: Input consumed by [`crate::runtime::json_commands::generated_surface_report_add_field_error`].
10325/// - `message`: Input consumed by [`crate::runtime::json_commands::generated_surface_report_add_field_error`].
10326///
10327/// # Returns
10328///
10329/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_report_add_field_error`] holds and `false` otherwise.
10330///
10331/// # Examples
10332///
10333/// ```rust,ignore
10334/// let _result = pharos_native::runtime::json_commands::generated_surface_report_add_field_error(todo!(), "field", "example");
10335/// ```
10336///
10337/// # Related
10338///
10339/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10340pub fn generated_surface_report_add_field_error(
10341    report: &mut Value,
10342    field: &str,
10343    message: &str,
10344) -> bool {
10345    if field.is_empty() || message.is_empty() {
10346        return false;
10347    }
10348    let Some(object) = report.as_object_mut() else {
10349        return false;
10350    };
10351    let errors = object
10352        .entry("field_errors".to_owned())
10353        .or_insert_with(|| Value::Object(Map::new()));
10354    let Some(error_map) = errors.as_object_mut() else {
10355        return false;
10356    };
10357    error_map.insert(field.to_owned(), Value::String(message.to_owned()));
10358    true
10359}
10360
10361/// Performs valid date text.
10362fn valid_date_text(text: &str) -> bool {
10363    let parts: Vec<_> = text.split('-').collect();
10364    parts.len() == 3
10365        && parts[0].len() == 4
10366        && parts[1].len() == 2
10367        && parts[2].len() == 2
10368        && parts
10369            .iter()
10370            .all(|part| part.bytes().all(|byte| byte.is_ascii_digit()))
10371        && (1..=12).contains(&parts[1].parse::<u8>().unwrap_or(0))
10372        && (1..=31).contains(&parts[2].parse::<u8>().unwrap_or(0))
10373}
10374
10375/// Validates the date text accepted by generated-surface filters.
10376///
10377/// # Parameters
10378///
10379/// - `text`: Input consumed by [`crate::runtime::json_commands::generated_surface_text_is_date`].
10380///
10381/// # Returns
10382///
10383/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_text_is_date`] holds and `false` otherwise.
10384///
10385/// # Examples
10386///
10387/// ```rust,ignore
10388/// let _result = pharos_native::runtime::json_commands::generated_surface_text_is_date("{}");
10389/// ```
10390///
10391/// # Related
10392///
10393/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10394pub fn generated_surface_text_is_date(text: &str) -> bool {
10395    valid_date_text(text)
10396}
10397
10398/// Validates a bounded decimal amount without accepting exponent syntax.
10399///
10400/// # Parameters
10401///
10402/// - `text`: Input consumed by [`crate::runtime::json_commands::generated_surface_text_is_decimal`].
10403///
10404/// # Returns
10405///
10406/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_text_is_decimal`] holds and `false` otherwise.
10407///
10408/// # Performance
10409///
10410/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_text_is_decimal`].
10411///
10412/// # Examples
10413///
10414/// ```rust,ignore
10415/// let _result = pharos_native::runtime::json_commands::generated_surface_text_is_decimal("{}");
10416/// ```
10417///
10418/// # Related
10419///
10420/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10421pub fn generated_surface_text_is_decimal(text: &str) -> bool {
10422    if text.is_empty() || text.len() > 64 {
10423        return false;
10424    }
10425    let mut separator_seen = false;
10426    let digits = text.strip_prefix('-').unwrap_or(text);
10427    !digits.is_empty()
10428        && digits.bytes().all(|byte| match byte {
10429            b'0'..=b'9' => true,
10430            b'.' if !separator_seen => {
10431                separator_seen = true;
10432                true
10433            }
10434            _ => false,
10435        })
10436}
10437
10438/// Validates a basic user-facing email value.
10439///
10440/// # Parameters
10441///
10442/// - `text`: Input consumed by [`crate::runtime::json_commands::generated_surface_text_is_email`].
10443///
10444/// # Returns
10445///
10446/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_text_is_email`] holds and `false` otherwise.
10447///
10448/// # Performance
10449///
10450/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_text_is_email`].
10451///
10452/// # Examples
10453///
10454/// ```rust,ignore
10455/// let _result = pharos_native::runtime::json_commands::generated_surface_text_is_email("{}");
10456/// ```
10457///
10458/// # Related
10459///
10460/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10461pub fn generated_surface_text_is_email(text: &str) -> bool {
10462    let Some((local, domain)) = text.split_once('@') else {
10463        return false;
10464    };
10465    !local.is_empty()
10466        && local.len() <= 128
10467        && !local.contains(char::is_whitespace)
10468        && domain.len() <= 253
10469        && domain.contains('.')
10470        && domain.split('.').all(|part| {
10471            !part.is_empty()
10472                && !part.starts_with('-')
10473                && !part.ends_with('-')
10474                && part
10475                    .bytes()
10476                    .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
10477        })
10478}
10479
10480/// Validates an HH:MM or HH:MM:SS time value.
10481///
10482/// # Parameters
10483///
10484/// - `text`: Input consumed by [`crate::runtime::json_commands::generated_surface_text_is_time`].
10485///
10486/// # Returns
10487///
10488/// Returns `true` when the condition checked by [`crate::runtime::json_commands::generated_surface_text_is_time`] holds and `false` otherwise.
10489///
10490/// # Performance
10491///
10492/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::generated_surface_text_is_time`].
10493///
10494/// # Examples
10495///
10496/// ```rust,ignore
10497/// let _result = pharos_native::runtime::json_commands::generated_surface_text_is_time("{}");
10498/// ```
10499///
10500/// # Related
10501///
10502/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10503pub fn generated_surface_text_is_time(text: &str) -> bool {
10504    let parts: Vec<_> = text.split(':').collect();
10505    (parts.len() == 2 || parts.len() == 3)
10506        && parts
10507            .iter()
10508            .all(|part| part.len() == 2 && part.bytes().all(|byte| byte.is_ascii_digit()))
10509        && parts[0].parse::<u8>().is_ok_and(|value| value < 24)
10510        && parts[1].parse::<u8>().is_ok_and(|value| value < 60)
10511        && parts
10512            .get(2)
10513            .is_none_or(|part| part.parse::<u8>().is_ok_and(|value| value < 60))
10514}
10515
10516/// Returns the greatest positive id in one state section.
10517///
10518/// # Parameters
10519///
10520/// - `root`: Input consumed by [`crate::runtime::json_commands::max_id_in_state_section`].
10521/// - `section`: Input consumed by [`crate::runtime::json_commands::max_id_in_state_section`].
10522///
10523/// # Returns
10524///
10525/// Returns the computed value produced by [`crate::runtime::json_commands::max_id_in_state_section`].
10526///
10527/// # Performance
10528///
10529/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::max_id_in_state_section`].
10530///
10531/// # Examples
10532///
10533/// ```rust,ignore
10534/// let _result = pharos_native::runtime::json_commands::max_id_in_state_section(std::path::Path::new("."), "items");
10535/// ```
10536///
10537/// # Related
10538///
10539/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10540pub fn max_id_in_state_section(root: &Value, section: &str) -> i64 {
10541    bounded_state_array(root, section)
10542        .iter()
10543        .filter_map(|row| row.get("id").and_then(Value::as_i64))
10544        .filter(|id| *id > 0)
10545        .max()
10546        .unwrap_or(0)
10547}
10548
10549/// Merges an object patch into a mutable object document.
10550///
10551/// # Parameters
10552///
10553/// - `target`: Input consumed by [`crate::runtime::json_commands::merge_patch_into_mut_object`].
10554/// - `patch`: Input consumed by [`crate::runtime::json_commands::merge_patch_into_mut_object`].
10555///
10556/// # Returns
10557///
10558/// Returns `true` when the condition checked by [`crate::runtime::json_commands::merge_patch_into_mut_object`] holds and `false` otherwise.
10559///
10560/// # Performance
10561///
10562/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::merge_patch_into_mut_object`].
10563///
10564/// # Examples
10565///
10566/// ```rust,ignore
10567/// let _result = pharos_native::runtime::json_commands::merge_patch_into_mut_object("/", todo!());
10568/// ```
10569///
10570/// # Related
10571///
10572/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10573pub fn merge_patch_into_mut_object(target: &mut Value, patch: &Value) -> bool {
10574    let (Some(target), Some(patch)) = (target.as_object_mut(), patch.as_object()) else {
10575        return false;
10576    };
10577    for (key, value) in patch {
10578        if value.is_null() {
10579            target.remove(key);
10580        } else {
10581            target.insert(key.clone(), value.clone());
10582        }
10583    }
10584    true
10585}
10586
10587/// Returns a mutable normalized payload object, rejecting non-object input.
10588///
10589/// # Parameters
10590///
10591/// - `value`: Input consumed by [`crate::runtime::json_commands::normalized_payload_object_mut`].
10592///
10593/// # Returns
10594///
10595/// Returns [`Some`] when [`crate::runtime::json_commands::normalized_payload_object_mut`] can produce a value and [`None`] otherwise.
10596///
10597/// # Examples
10598///
10599/// ```rust,ignore
10600/// let _result = pharos_native::runtime::json_commands::normalized_payload_object_mut("value");
10601/// ```
10602///
10603/// # Related
10604///
10605/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10606pub fn normalized_payload_object_mut(value: &mut Value) -> Option<&mut Map<String, Value>> {
10607    value.as_object_mut()
10608}
10609
10610/// Returns the JSON text for a user's booking selected by user id.
10611///
10612/// # Parameters
10613///
10614/// - `root`: Input consumed by [`crate::runtime::json_commands::state_find_booking_for_user`].
10615/// - `user_id`: Input consumed by [`crate::runtime::json_commands::state_find_booking_for_user`].
10616///
10617/// # Returns
10618///
10619/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_booking_for_user`] can produce a value and [`None`] otherwise.
10620///
10621/// # Performance
10622///
10623/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_find_booking_for_user`].
10624///
10625/// # Examples
10626///
10627/// ```rust,ignore
10628/// let _result = pharos_native::runtime::json_commands::state_find_booking_for_user(std::path::Path::new("."), 1);
10629/// ```
10630///
10631/// # Related
10632///
10633/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10634pub fn state_find_booking_for_user(root: &Value, user_id: i64) -> Option<String> {
10635    bounded_state_array(root, "bookings")
10636        .iter()
10637        .find(|row| row.get("user_id").and_then(Value::as_i64) == Some(user_id))
10638        .and_then(compact)
10639}
10640
10641/// Returns the JSON text for a record selected by a string field.
10642///
10643/// # Parameters
10644///
10645/// - `root`: Input consumed by [`crate::runtime::json_commands::surface_find_record_by_string_field`].
10646/// - `section`: Input consumed by [`crate::runtime::json_commands::surface_find_record_by_string_field`].
10647/// - `field`: Input consumed by [`crate::runtime::json_commands::surface_find_record_by_string_field`].
10648/// - `expected`: Input consumed by [`crate::runtime::json_commands::surface_find_record_by_string_field`].
10649///
10650/// # Returns
10651///
10652/// Returns [`Some`] when [`crate::runtime::json_commands::surface_find_record_by_string_field`] can produce a value and [`None`] otherwise.
10653///
10654/// # Performance
10655///
10656/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::surface_find_record_by_string_field`].
10657///
10658/// # Examples
10659///
10660/// ```rust,ignore
10661/// let _result = pharos_native::runtime::json_commands::surface_find_record_by_string_field(std::path::Path::new("."), "items", "field", "value");
10662/// ```
10663///
10664/// # Related
10665///
10666/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10667pub fn surface_find_record_by_string_field(
10668    root: &Value,
10669    section: &str,
10670    field: &str,
10671    expected: &str,
10672) -> Option<String> {
10673    bounded_state_array(root, section)
10674        .iter()
10675        .find(|row| row.get(field).and_then(Value::as_str) == Some(expected))
10676        .and_then(compact)
10677}
10678
10679/// Emits active tenant identifiers for one user as newline-delimited text.
10680///
10681/// # Parameters
10682///
10683/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_active_tenant_ids_lines`].
10684/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_active_tenant_ids_lines`].
10685///
10686/// # Returns
10687///
10688/// Returns the computed value produced by [`crate::runtime::json_commands::emit_active_tenant_ids_lines`].
10689///
10690/// # Performance
10691///
10692/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_active_tenant_ids_lines`].
10693///
10694/// # Examples
10695///
10696/// ```rust,ignore
10697/// let _result = pharos_native::runtime::json_commands::emit_active_tenant_ids_lines(std::path::Path::new("."), 1);
10698/// ```
10699///
10700/// # Related
10701///
10702/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10703pub fn emit_active_tenant_ids_lines(root: &Value, user_id: i64) -> String {
10704    bounded_state_array(root, "tenant_memberships")
10705        .iter()
10706        .filter(|row| row.get("user_id").and_then(Value::as_i64) == Some(user_id))
10707        .filter(|row| {
10708            row.get("membership_status")
10709                .and_then(Value::as_str)
10710                .is_none_or(|status| status.is_empty() || status == "active")
10711        })
10712        .filter_map(|row| row.get("tenant_id").and_then(Value::as_i64))
10713        .take(MAX_OUTPUT_ROWS_JSON)
10714        .map(|id| id.to_string())
10715        .collect::<Vec<_>>()
10716        .join("\n")
10717}
10718
10719/// Performs rows as JSON.
10720fn rows_as_json(root: &Value, section: &str, predicate: impl Fn(&Value) -> bool) -> Option<String> {
10721    let rows: Vec<Value> = bounded_state_array(root, section)
10722        .iter()
10723        .filter(|row| predicate(row))
10724        .take(MAX_OUTPUT_ROWS_JSON)
10725        .cloned()
10726        .collect();
10727    compact(&Value::Array(rows))
10728}
10729
10730/// Emits appointments visible to one user.
10731///
10732/// # Parameters
10733///
10734/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_user_appointments`].
10735/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_user_appointments`].
10736///
10737/// # Returns
10738///
10739/// Returns [`Some`] when [`crate::runtime::json_commands::emit_user_appointments`] can produce a value and [`None`] otherwise.
10740///
10741/// # Examples
10742///
10743/// ```rust,ignore
10744/// let _result = pharos_native::runtime::json_commands::emit_user_appointments(std::path::Path::new("."), 1);
10745/// ```
10746///
10747/// # Related
10748///
10749/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10750pub fn emit_user_appointments(root: &Value, user_id: i64) -> Option<String> {
10751    rows_as_json(root, "appointments", |row| {
10752        row.get("user_id").and_then(Value::as_i64) == Some(user_id)
10753    })
10754}
10755
10756/// Emits appointments visible to a managed user, preserving state order.
10757///
10758/// # Parameters
10759///
10760/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_managed_appointments`].
10761/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_managed_appointments`].
10762///
10763/// # Returns
10764///
10765/// Returns [`Some`] when [`crate::runtime::json_commands::emit_managed_appointments`] can produce a value and [`None`] otherwise.
10766///
10767/// # Performance
10768///
10769/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_managed_appointments`].
10770///
10771/// # Examples
10772///
10773/// ```rust,ignore
10774/// let _result = pharos_native::runtime::json_commands::emit_managed_appointments(std::path::Path::new("."), 1);
10775/// ```
10776///
10777/// # Related
10778///
10779/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10780pub fn emit_managed_appointments(root: &Value, user_id: i64) -> Option<String> {
10781    let business_ids: Vec<i64> = bounded_state_array(root, "businesses")
10782        .iter()
10783        .filter(|row| row.get("owner_id").and_then(Value::as_i64) == Some(user_id))
10784        .filter_map(|row| row.get("id").and_then(Value::as_i64))
10785        .collect();
10786    rows_as_json(root, "appointments", |row| {
10787        row.get("business_id")
10788            .and_then(Value::as_i64)
10789            .is_some_and(|id| business_ids.contains(&id))
10790    })
10791}
10792
10793/// Emits the tenant ids associated with one user's active memberships as JSON.
10794///
10795/// # Parameters
10796///
10797/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_user_membership_tenant_ids`].
10798/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_user_membership_tenant_ids`].
10799///
10800/// # Returns
10801///
10802/// Returns [`Some`] when [`crate::runtime::json_commands::emit_user_membership_tenant_ids`] can produce a value and [`None`] otherwise.
10803///
10804/// # Performance
10805///
10806/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_user_membership_tenant_ids`].
10807///
10808/// # Examples
10809///
10810/// ```rust,ignore
10811/// let _result = pharos_native::runtime::json_commands::emit_user_membership_tenant_ids(std::path::Path::new("."), 1);
10812/// ```
10813///
10814/// # Related
10815///
10816/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10817pub fn emit_user_membership_tenant_ids(root: &Value, user_id: i64) -> Option<String> {
10818    let ids: Vec<Value> = bounded_state_array(root, "tenant_memberships")
10819        .iter()
10820        .filter(|row| row.get("user_id").and_then(Value::as_i64) == Some(user_id))
10821        .filter(|row| {
10822            row.get("membership_status")
10823                .and_then(Value::as_str)
10824                .is_none_or(|status| status.is_empty() || status == "active")
10825        })
10826        .filter_map(|row| row.get("tenant_id").cloned())
10827        .take(MAX_OUTPUT_ROWS_JSON)
10828        .collect();
10829    compact(&Value::Array(ids))
10830}
10831
10832/// Emits public business cards from state.
10833///
10834/// # Parameters
10835///
10836/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_public_business_cards`].
10837///
10838/// # Returns
10839///
10840/// Returns [`Some`] when [`crate::runtime::json_commands::emit_public_business_cards`] can produce a value and [`None`] otherwise.
10841///
10842/// # Performance
10843///
10844/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_public_business_cards`].
10845///
10846/// # Examples
10847///
10848/// ```rust,ignore
10849/// let _result = pharos_native::runtime::json_commands::emit_public_business_cards(std::path::Path::new("."));
10850/// ```
10851///
10852/// # Related
10853///
10854/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10855pub fn emit_public_business_cards(root: &Value) -> Option<String> {
10856    let cards: Vec<Value> = bounded_state_array(root, "businesses")
10857        .iter()
10858        .map(|row| serde_json::json!({"id": row.get("id").cloned().unwrap_or(Value::Null), "slug": row.get("slug").cloned().unwrap_or(Value::Null), "name": row.get("name").cloned().unwrap_or(Value::Null), "description": row.get("description").cloned().unwrap_or(Value::Null), "image_url": row.get("image_url").cloned().unwrap_or(Value::Null)}))
10859        .take(MAX_OUTPUT_ROWS_JSON)
10860        .collect();
10861    compact(&Value::Array(cards))
10862}
10863
10864/// Emits business cards managed by one user.
10865///
10866/// # Parameters
10867///
10868/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_manageable_business_cards`].
10869/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_manageable_business_cards`].
10870///
10871/// # Returns
10872///
10873/// Returns [`Some`] when [`crate::runtime::json_commands::emit_manageable_business_cards`] can produce a value and [`None`] otherwise.
10874///
10875/// # Performance
10876///
10877/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_manageable_business_cards`].
10878///
10879/// # Examples
10880///
10881/// ```rust,ignore
10882/// let _result = pharos_native::runtime::json_commands::emit_manageable_business_cards(std::path::Path::new("."), 1);
10883/// ```
10884///
10885/// # Related
10886///
10887/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10888pub fn emit_manageable_business_cards(root: &Value, user_id: i64) -> Option<String> {
10889    let cards: Vec<Value> = bounded_state_array(root, "businesses")
10890        .iter()
10891        .filter(|row| {
10892            row.get("owner_id").and_then(Value::as_i64) == Some(user_id)
10893                || row.get("owner_user_id").and_then(Value::as_i64) == Some(user_id)
10894        })
10895        .take(MAX_OUTPUT_ROWS_JSON)
10896        .cloned()
10897        .collect();
10898    compact(&Value::Array(cards))
10899}
10900
10901/// Writes a bounded mutable JSON document through the native filesystem surface.
10902///
10903/// # Parameters
10904///
10905/// - `path`: Input consumed by [`crate::runtime::json_commands::write_mutable_json_doc`].
10906/// - `value`: Input consumed by [`crate::runtime::json_commands::write_mutable_json_doc`].
10907///
10908/// # Returns
10909///
10910/// Returns the computed value produced by [`crate::runtime::json_commands::write_mutable_json_doc`].
10911///
10912/// # Examples
10913///
10914/// ```rust,ignore
10915/// let _result = pharos_native::runtime::json_commands::write_mutable_json_doc(std::path::Path::new("fixture.json"), "value");
10916/// ```
10917///
10918/// # Related
10919///
10920/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10921pub fn write_mutable_json_doc(path: &Path, value: &Value) -> i32 {
10922    let Some(text) = compact(value) else {
10923        return 75;
10924    };
10925    super::fs::write_text_file(path, &text)
10926}
10927
10928/// Compacts a mutable JSON document read from disk.
10929///
10930/// # Parameters
10931///
10932/// - `path`: Input consumed by [`crate::runtime::json_commands::emit_compact_mutable_json_doc`].
10933///
10934/// # Returns
10935///
10936/// Returns [`Some`] when [`crate::runtime::json_commands::emit_compact_mutable_json_doc`] can produce a value and [`None`] otherwise.
10937///
10938/// # Examples
10939///
10940/// ```rust,ignore
10941/// let _result = pharos_native::runtime::json_commands::emit_compact_mutable_json_doc(std::path::Path::new("fixture.json"));
10942/// ```
10943///
10944/// # Related
10945///
10946/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10947pub fn emit_compact_mutable_json_doc(path: &Path) -> Option<String> {
10948    compact(&read_json_file(path)?)
10949}
10950
10951/// Captures a stable checksum string using the configured native checksum tool.
10952///
10953/// # Parameters
10954///
10955/// - `value`: Input consumed by [`crate::runtime::json_commands::capture_checksum_output`].
10956///
10957/// # Returns
10958///
10959/// Returns [`Some`] when [`crate::runtime::json_commands::capture_checksum_output`] can produce a value and [`None`] otherwise.
10960///
10961/// # Examples
10962///
10963/// ```rust,ignore
10964/// let _result = pharos_native::runtime::json_commands::capture_checksum_output("value");
10965/// ```
10966///
10967/// # Related
10968///
10969/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10970pub fn capture_checksum_output(value: &str) -> Option<String> {
10971    checksum_string(value)
10972}
10973
10974/// Returns a JSON value with its template text rendered from bounded parameters.
10975///
10976/// # Parameters
10977///
10978/// - `template_path`: Input consumed by [`crate::runtime::json_commands::emit_template`].
10979/// - `params_json`: Input consumed by [`crate::runtime::json_commands::emit_template`].
10980///
10981/// # Returns
10982///
10983/// Returns [`Some`] when [`crate::runtime::json_commands::emit_template`] can produce a value and [`None`] otherwise.
10984///
10985/// # Examples
10986///
10987/// ```rust,ignore
10988/// let _result = pharos_native::runtime::json_commands::emit_template("template.html", todo!());
10989/// ```
10990///
10991/// # Related
10992///
10993/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
10994pub fn emit_template(template_path: &Path, params_json: &str) -> Option<String> {
10995    let params = object_from_text(params_json)?;
10996    render_file_template(template_path, &params)
10997}
10998
10999/// Emits an escaped text line without writing to a process-global stream.
11000///
11001/// # Parameters
11002///
11003/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_sorted_section_lines`].
11004/// - `section`: Input consumed by [`crate::runtime::json_commands::emit_sorted_section_lines`].
11005/// - `field`: Input consumed by [`crate::runtime::json_commands::emit_sorted_section_lines`].
11006///
11007/// # Returns
11008///
11009/// Returns [`Some`] when [`crate::runtime::json_commands::emit_sorted_section_lines`] can produce a value and [`None`] otherwise.
11010///
11011/// # Performance
11012///
11013/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_sorted_section_lines`].
11014///
11015/// # Examples
11016///
11017/// ```rust,ignore
11018/// let _result = pharos_native::runtime::json_commands::emit_sorted_section_lines(std::path::Path::new("."), "items", "field");
11019/// ```
11020///
11021/// # Related
11022///
11023/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11024pub fn emit_sorted_section_lines(root: &Value, section: &str, field: &str) -> Option<String> {
11025    let mut values: Vec<String> = bounded_state_array(root, section)
11026        .iter()
11027        .filter_map(|row| row.get(field).map(value_to_text))
11028        .filter(|value| !value.is_empty())
11029        .collect();
11030    values.sort();
11031    values.dedup();
11032    Some(values.join("\n"))
11033}
11034
11035/// Emits template page parameters as compact JSON.
11036///
11037/// # Parameters
11038///
11039/// - `params`: Input consumed by [`crate::runtime::json_commands::emit_template_page_params`].
11040///
11041/// # Returns
11042///
11043/// Returns [`Some`] when [`crate::runtime::json_commands::emit_template_page_params`] can produce a value and [`None`] otherwise.
11044///
11045/// # Examples
11046///
11047/// ```rust,ignore
11048/// let _result = pharos_native::runtime::json_commands::emit_template_page_params(todo!());
11049/// ```
11050///
11051/// # Related
11052///
11053/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11054pub fn emit_template_page_params(params: &Value) -> Option<String> {
11055    compact(params)
11056}
11057
11058/// Appends a text line to a bounded output buffer.
11059///
11060/// # Parameters
11061///
11062/// - `output`: Input consumed by [`crate::runtime::json_commands::emit_text_line_to_buffer`].
11063/// - `text`: Input consumed by [`crate::runtime::json_commands::emit_text_line_to_buffer`].
11064///
11065/// # Returns
11066///
11067/// Returns `true` when the condition checked by [`crate::runtime::json_commands::emit_text_line_to_buffer`] holds and `false` otherwise.
11068///
11069/// # Examples
11070///
11071/// ```rust,ignore
11072/// let _result = pharos_native::runtime::json_commands::emit_text_line_to_buffer(todo!(), "{}");
11073/// ```
11074///
11075/// # Related
11076///
11077/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11078pub fn emit_text_line_to_buffer(output: &mut String, text: &str) -> bool {
11079    let Some(line) = emit_text_line(text) else {
11080        return false;
11081    };
11082    if output.len().saturating_add(line.len()) > MAX_TEXT_BYTES {
11083        return false;
11084    }
11085    output.push_str(&line);
11086    true
11087}
11088
11089/// Returns a mutable state row selected by a positive integer field.
11090///
11091/// # Parameters
11092///
11093/// - `root`: Input consumed by [`crate::runtime::json_commands::find_mut_array_item_by_long_field`].
11094/// - `section`: Input consumed by [`crate::runtime::json_commands::find_mut_array_item_by_long_field`].
11095/// - `field`: Input consumed by [`crate::runtime::json_commands::find_mut_array_item_by_long_field`].
11096/// - `wanted`: Input consumed by [`crate::runtime::json_commands::find_mut_array_item_by_long_field`].
11097///
11098/// # Returns
11099///
11100/// Returns [`Some`] when [`crate::runtime::json_commands::find_mut_array_item_by_long_field`] can produce a value and [`None`] otherwise.
11101///
11102/// # Performance
11103///
11104/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_mut_array_item_by_long_field`].
11105///
11106/// # Examples
11107///
11108/// ```rust,ignore
11109/// let _result = pharos_native::runtime::json_commands::find_mut_array_item_by_long_field(std::path::Path::new("."), "items", "field", todo!());
11110/// ```
11111///
11112/// # Related
11113///
11114/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11115pub fn find_mut_array_item_by_long_field<'a>(
11116    root: &'a mut Value,
11117    section: &str,
11118    field: &str,
11119    wanted: i64,
11120) -> Option<&'a mut Value> {
11121    if section.is_empty() || field.is_empty() || wanted <= 0 {
11122        return None;
11123    }
11124    root.get_mut(section)?
11125        .as_array_mut()?
11126        .iter_mut()
11127        .find(|item| item.get(field).and_then(Value::as_i64) == Some(wanted))
11128}
11129
11130/// Finds an active token record for one user and token value.
11131///
11132/// # Parameters
11133///
11134/// - `root`: Input consumed by [`crate::runtime::json_commands::find_active_token_record`].
11135/// - `user_id`: Input consumed by [`crate::runtime::json_commands::find_active_token_record`].
11136/// - `token`: Input consumed by [`crate::runtime::json_commands::find_active_token_record`].
11137///
11138/// # Returns
11139///
11140/// Returns [`Some`] when [`crate::runtime::json_commands::find_active_token_record`] can produce a value and [`None`] otherwise.
11141///
11142/// # Performance
11143///
11144/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_active_token_record`].
11145///
11146/// # Examples
11147///
11148/// ```rust,ignore
11149/// let _result = pharos_native::runtime::json_commands::find_active_token_record(std::path::Path::new("."), 1, todo!());
11150/// ```
11151///
11152/// # Related
11153///
11154/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11155pub fn find_active_token_record(root: &Value, user_id: i64, token: &str) -> Option<String> {
11156    if user_id <= 0 || token.is_empty() {
11157        return None;
11158    }
11159    bounded_state_array(root, "tokens")
11160        .iter()
11161        .find(|row| {
11162            row.get("user_id").and_then(Value::as_i64) == Some(user_id)
11163                && row.get("token").and_then(Value::as_str) == Some(token)
11164                && row.get("revoked").and_then(Value::as_bool) != Some(true)
11165        })
11166        .and_then(compact)
11167}
11168
11169/// Normalizes one persisted runtime state file and returns its compact text.
11170///
11171/// # Parameters
11172///
11173/// - `path`: Input consumed by [`crate::runtime::json_commands::handle_file_normalize_runtime_state_command`].
11174///
11175/// # Returns
11176///
11177/// Returns the successful value produced by [`crate::runtime::json_commands::handle_file_normalize_runtime_state_command`] or an error when the operation fails.
11178///
11179/// # Errors
11180///
11181/// Returns an error value when [`crate::runtime::json_commands::handle_file_normalize_runtime_state_command`] cannot complete successfully.
11182///
11183/// # Examples
11184///
11185/// ```rust,ignore
11186/// let _result = pharos_native::runtime::json_commands::handle_file_normalize_runtime_state_command(std::path::Path::new("fixture.json"));
11187/// ```
11188///
11189/// # Related
11190///
11191/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11192pub fn handle_file_normalize_runtime_state_command(path: &Path) -> Result<String, i32> {
11193    let root = read_json_file(path).ok_or(66)?;
11194    let text = compact(&root).ok_or(75)?;
11195    if super::fs::write_text_file(path, &text) != 0 {
11196        return Err(73);
11197    }
11198    Ok(text)
11199}
11200
11201/// Matches a route template and stores its path parameters in an object.
11202///
11203/// # Parameters
11204///
11205/// - `output`: Input consumed by [`crate::runtime::json_commands::route_template_match_into_mut_obj`].
11206/// - `template_path`: Input consumed by [`crate::runtime::json_commands::route_template_match_into_mut_obj`].
11207/// - `request_path`: Input consumed by [`crate::runtime::json_commands::route_template_match_into_mut_obj`].
11208///
11209/// # Returns
11210///
11211/// Returns `true` when the condition checked by [`crate::runtime::json_commands::route_template_match_into_mut_obj`] holds and `false` otherwise.
11212///
11213/// # Examples
11214///
11215/// ```rust,ignore
11216/// let _result = pharos_native::runtime::json_commands::route_template_match_into_mut_obj(todo!(), "template.html", "/");
11217/// ```
11218///
11219/// # Related
11220///
11221/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11222pub fn route_template_match_into_mut_obj(
11223    output: &mut Map<String, Value>,
11224    template_path: &str,
11225    request_path: &str,
11226) -> bool {
11227    let Some(params) = route_template_params(template_path, request_path) else {
11228        return false;
11229    };
11230    output.extend(params);
11231    true
11232}
11233
11234/// Handles the state event-row JSON command from an already-loaded row.
11235///
11236/// # Parameters
11237///
11238/// - `row`: Input consumed by [`crate::runtime::json_commands::handle_state_event_stream_row_json_lines_command`].
11239///
11240/// # Returns
11241///
11242/// Returns [`Some`] when [`crate::runtime::json_commands::handle_state_event_stream_row_json_lines_command`] can produce a value and [`None`] otherwise.
11243///
11244/// # Examples
11245///
11246/// ```rust,ignore
11247/// let _result = pharos_native::runtime::json_commands::handle_state_event_stream_row_json_lines_command(todo!());
11248/// ```
11249///
11250/// # Related
11251///
11252/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11253pub fn handle_state_event_stream_row_json_lines_command(row: &Value) -> Option<String> {
11254    compact(row)
11255}
11256
11257/// Handles importing one bounded JSON row into a mutable state document.
11258///
11259/// # Parameters
11260///
11261/// - `root`: Input consumed by [`crate::runtime::json_commands::handle_state_import_row_json_lines_command`].
11262/// - `row_text`: Input consumed by [`crate::runtime::json_commands::handle_state_import_row_json_lines_command`].
11263///
11264/// # Returns
11265///
11266/// Returns the successful value produced by [`crate::runtime::json_commands::handle_state_import_row_json_lines_command`] or an error when the operation fails.
11267///
11268/// # Errors
11269///
11270/// Returns an error value when [`crate::runtime::json_commands::handle_state_import_row_json_lines_command`] cannot complete successfully.
11271///
11272/// # Performance
11273///
11274/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_state_import_row_json_lines_command`].
11275///
11276/// # Examples
11277///
11278/// ```rust,ignore
11279/// let _result = pharos_native::runtime::json_commands::handle_state_import_row_json_lines_command(std::path::Path::new("."), todo!());
11280/// ```
11281///
11282/// # Related
11283///
11284/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11285pub fn handle_state_import_row_json_lines_command(
11286    root: &mut Value,
11287    row_text: &str,
11288) -> Result<String, i32> {
11289    let row = serde_json::from_str::<Value>(row_text).map_err(|_| 65)?;
11290    if !row.is_object() || !generated_surface_append_audit_event_mut(root, row.clone()) {
11291        return Err(65);
11292    }
11293    compact(&row).ok_or(75)
11294}
11295
11296/// Applies a template base path to URL-bearing attributes.
11297///
11298/// # Parameters
11299///
11300/// - `html`: Input consumed by [`crate::runtime::json_commands::handle_template_apply_base_path_command`].
11301/// - `base_path`: Input consumed by [`crate::runtime::json_commands::handle_template_apply_base_path_command`].
11302///
11303/// # Returns
11304///
11305/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_apply_base_path_command`] can produce a value and [`None`] otherwise.
11306///
11307/// # Examples
11308///
11309/// ```rust,ignore
11310/// let _result = pharos_native::runtime::json_commands::handle_template_apply_base_path_command(todo!(), "/app");
11311/// ```
11312///
11313/// # Related
11314///
11315/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11316pub fn handle_template_apply_base_path_command(
11317    html: &str,
11318    base_path: Option<&str>,
11319) -> Option<String> {
11320    template_apply_base_path(html, base_path)
11321}
11322
11323/// Resolves a declared fragment path for a command caller.
11324///
11325/// # Parameters
11326///
11327/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_template_declared_fragment_path_command`].
11328/// - `fragment_id`: Input consumed by [`crate::runtime::json_commands::handle_template_declared_fragment_path_command`].
11329///
11330/// # Returns
11331///
11332/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_declared_fragment_path_command`] can produce a value and [`None`] otherwise.
11333///
11334/// # Examples
11335///
11336/// ```rust,ignore
11337/// let _result = pharos_native::runtime::json_commands::handle_template_declared_fragment_path_command(std::path::Path::new("apps/dev_docs"), "header");
11338/// ```
11339///
11340/// # Related
11341///
11342/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11343pub fn handle_template_declared_fragment_path_command(
11344    app_root: &Path,
11345    fragment_id: &str,
11346) -> Option<String> {
11347    template_declared_fragment_path(app_root, fragment_id)
11348}
11349
11350/// Resolves a declared page contract for a command caller.
11351///
11352/// # Parameters
11353///
11354/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_template_declared_page_contract_command`].
11355/// - `page_id`: Input consumed by [`crate::runtime::json_commands::handle_template_declared_page_contract_command`].
11356///
11357/// # Returns
11358///
11359/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_declared_page_contract_command`] can produce a value and [`None`] otherwise.
11360///
11361/// # Examples
11362///
11363/// ```rust,ignore
11364/// let _result = pharos_native::runtime::json_commands::handle_template_declared_page_contract_command(std::path::Path::new("apps/dev_docs"), "home");
11365/// ```
11366///
11367/// # Related
11368///
11369/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11370pub fn handle_template_declared_page_contract_command(
11371    app_root: &Path,
11372    page_id: &str,
11373) -> Option<String> {
11374    template_declared_page_contract(app_root, page_id)
11375}
11376
11377/// Renders one named page JSON contract from a parameter document.
11378///
11379/// # Parameters
11380///
11381/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_template_layout_page_json_command`].
11382/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_layout_page_json_command`].
11383///
11384/// # Returns
11385///
11386/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_layout_page_json_command`] can produce a value and [`None`] otherwise.
11387///
11388/// # Examples
11389///
11390/// ```rust,ignore
11391/// let _result = pharos_native::runtime::json_commands::handle_template_layout_page_json_command(std::path::Path::new("apps/dev_docs"), todo!());
11392/// ```
11393///
11394/// # Related
11395///
11396/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11397pub fn handle_template_layout_page_json_command(
11398    app_root: &Path,
11399    params_json: &str,
11400) -> Option<String> {
11401    let params = object_from_text(params_json)?;
11402    template_layout_page_json(
11403        app_root,
11404        params.get("layout_id").and_then(Value::as_str),
11405        params.get("current_lang").and_then(Value::as_str),
11406        params
11407            .get("title")
11408            .and_then(Value::as_str)
11409            .unwrap_or_default(),
11410        params
11411            .get("body")
11412            .and_then(Value::as_str)
11413            .unwrap_or_default(),
11414        params.get("current_request_target").and_then(Value::as_str),
11415        params
11416            .get("has_user")
11417            .and_then(Value::as_bool)
11418            .unwrap_or(false),
11419        params
11420            .get("managed_business_count")
11421            .and_then(Value::as_i64)
11422            .unwrap_or(0),
11423    )
11424}
11425
11426/// Renders one named layout page as HTML from a parameter document.
11427///
11428/// # Parameters
11429///
11430/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_template_layout_page_html_command`].
11431/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_layout_page_html_command`].
11432///
11433/// # Returns
11434///
11435/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_layout_page_html_command`] can produce a value and [`None`] otherwise.
11436///
11437/// # Examples
11438///
11439/// ```rust,ignore
11440/// let _result = pharos_native::runtime::json_commands::handle_template_layout_page_html_command(std::path::Path::new("apps/dev_docs"), todo!());
11441/// ```
11442///
11443/// # Related
11444///
11445/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11446pub fn handle_template_layout_page_html_command(
11447    app_root: &Path,
11448    params_json: &str,
11449) -> Option<String> {
11450    let params = object_from_text(params_json)?;
11451    template_layout_page_html(
11452        app_root,
11453        params.get("base_path").and_then(Value::as_str),
11454        params.get("layout_id").and_then(Value::as_str),
11455        params.get("current_lang").and_then(Value::as_str),
11456        params
11457            .get("title")
11458            .and_then(Value::as_str)
11459            .unwrap_or_default(),
11460        params
11461            .get("body")
11462            .and_then(Value::as_str)
11463            .unwrap_or_default(),
11464        params.get("current_request_target").and_then(Value::as_str),
11465        params
11466            .get("has_user")
11467            .and_then(Value::as_bool)
11468            .unwrap_or(false),
11469        params
11470            .get("managed_business_count")
11471            .and_then(Value::as_i64)
11472            .unwrap_or(0),
11473    )
11474}
11475
11476/// Performs template command params.
11477fn template_command_params(params_json: &str) -> Option<Value> {
11478    let params = serde_json::from_str::<Value>(params_json).ok()?;
11479    params.is_object().then_some(params)
11480}
11481
11482/// Builds the login page parameter JSON for a command caller.
11483///
11484/// # Parameters
11485///
11486/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_login_page_json_command`].
11487///
11488/// # Returns
11489///
11490/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_login_page_json_command`] can produce a value and [`None`] otherwise.
11491///
11492/// # Examples
11493///
11494/// ```rust,ignore
11495/// let _result = pharos_native::runtime::json_commands::handle_template_login_page_json_command(todo!());
11496/// ```
11497///
11498/// # Related
11499///
11500/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11501pub fn handle_template_login_page_json_command(params_json: &str) -> Option<String> {
11502    let params = template_command_params(params_json)?;
11503    compact(&params)
11504}
11505
11506/// Builds the registration page parameter JSON for a command caller.
11507///
11508/// # Parameters
11509///
11510/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_register_page_json_command`].
11511///
11512/// # Returns
11513///
11514/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_register_page_json_command`] can produce a value and [`None`] otherwise.
11515///
11516/// # Examples
11517///
11518/// ```rust,ignore
11519/// let _result = pharos_native::runtime::json_commands::handle_template_register_page_json_command(todo!());
11520/// ```
11521///
11522/// # Related
11523///
11524/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11525pub fn handle_template_register_page_json_command(params_json: &str) -> Option<String> {
11526    let params = template_command_params(params_json)?;
11527    compact(&params)
11528}
11529
11530/// Builds the password-reset request page parameter JSON.
11531///
11532/// # Parameters
11533///
11534/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_password_reset_request_page_json_command`].
11535///
11536/// # Returns
11537///
11538/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_password_reset_request_page_json_command`] can produce a value and [`None`] otherwise.
11539///
11540/// # Examples
11541///
11542/// ```rust,ignore
11543/// let _result = pharos_native::runtime::json_commands::handle_template_password_reset_request_page_json_command(todo!());
11544/// ```
11545///
11546/// # Related
11547///
11548/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11549pub fn handle_template_password_reset_request_page_json_command(
11550    params_json: &str,
11551) -> Option<String> {
11552    let params = template_command_params(params_json)?;
11553    compact(&params)
11554}
11555
11556/// Builds the password-reset sent page parameter JSON.
11557///
11558/// # Parameters
11559///
11560/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_password_reset_sent_page_json_command`].
11561///
11562/// # Returns
11563///
11564/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_password_reset_sent_page_json_command`] can produce a value and [`None`] otherwise.
11565///
11566/// # Examples
11567///
11568/// ```rust,ignore
11569/// let _result = pharos_native::runtime::json_commands::handle_template_password_reset_sent_page_json_command(todo!());
11570/// ```
11571///
11572/// # Related
11573///
11574/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11575pub fn handle_template_password_reset_sent_page_json_command(params_json: &str) -> Option<String> {
11576    let params = template_command_params(params_json)?;
11577    compact(&params)
11578}
11579
11580/// Builds the password-reset complete page parameter JSON.
11581///
11582/// # Parameters
11583///
11584/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_password_reset_complete_page_json_command`].
11585///
11586/// # Returns
11587///
11588/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_password_reset_complete_page_json_command`] can produce a value and [`None`] otherwise.
11589///
11590/// # Examples
11591///
11592/// ```rust,ignore
11593/// let _result = pharos_native::runtime::json_commands::handle_template_password_reset_complete_page_json_command(todo!());
11594/// ```
11595///
11596/// # Related
11597///
11598/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11599pub fn handle_template_password_reset_complete_page_json_command(
11600    params_json: &str,
11601) -> Option<String> {
11602    let params = template_command_params(params_json)?;
11603    compact(&params)
11604}
11605
11606/// Builds the invite-created page parameter JSON.
11607///
11608/// # Parameters
11609///
11610/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_invite_created_page_json_command`].
11611///
11612/// # Returns
11613///
11614/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_invite_created_page_json_command`] can produce a value and [`None`] otherwise.
11615///
11616/// # Examples
11617///
11618/// ```rust,ignore
11619/// let _result = pharos_native::runtime::json_commands::handle_template_invite_created_page_json_command(todo!());
11620/// ```
11621///
11622/// # Related
11623///
11624/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11625pub fn handle_template_invite_created_page_json_command(params_json: &str) -> Option<String> {
11626    let params = template_command_params(params_json)?;
11627    compact(&params)
11628}
11629
11630/// Builds the invite-accept page parameter JSON.
11631///
11632/// # Parameters
11633///
11634/// - `params_json`: Input consumed by [`crate::runtime::json_commands::handle_template_invite_accept_page_json_command`].
11635///
11636/// # Returns
11637///
11638/// Returns [`Some`] when [`crate::runtime::json_commands::handle_template_invite_accept_page_json_command`] can produce a value and [`None`] otherwise.
11639///
11640/// # Examples
11641///
11642/// ```rust,ignore
11643/// let _result = pharos_native::runtime::json_commands::handle_template_invite_accept_page_json_command(todo!());
11644/// ```
11645///
11646/// # Related
11647///
11648/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11649pub fn handle_template_invite_accept_page_json_command(params_json: &str) -> Option<String> {
11650    let params = template_command_params(params_json)?;
11651    compact(&params)
11652}
11653
11654/// Renders a shared empty fragment through the declared application template.
11655///
11656/// # Parameters
11657///
11658/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_app_empty_fragment`].
11659/// - `message`: Input consumed by [`crate::runtime::json_commands::render_app_empty_fragment`].
11660///
11661/// # Returns
11662///
11663/// Returns [`Some`] when [`crate::runtime::json_commands::render_app_empty_fragment`] can produce a value and [`None`] otherwise.
11664///
11665/// # Examples
11666///
11667/// ```rust,ignore
11668/// let _result = pharos_native::runtime::json_commands::render_app_empty_fragment(std::path::Path::new("apps/dev_docs"), "example");
11669/// ```
11670///
11671/// # Related
11672///
11673/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11674pub fn render_app_empty_fragment(app_root: &Path, message: &str) -> Option<String> {
11675    let params = Map::from_iter([("message".to_owned(), Value::String(message.to_owned()))]);
11676    generated::render_generated_admin_fragment_from_value_runtime(
11677        app_root,
11678        "templates/shared/fragments/empty.html",
11679        &params,
11680    )
11681}
11682
11683/// Returns the declared empty dashboard copy without embedding a page shell.
11684///
11685/// # Parameters
11686///
11687/// - `message`: Input consumed by [`crate::runtime::json_commands::render_business_dashboard_empty_html`].
11688///
11689/// # Returns
11690///
11691/// Returns the computed value produced by [`crate::runtime::json_commands::render_business_dashboard_empty_html`].
11692///
11693/// # Examples
11694///
11695/// ```rust,ignore
11696/// let _result = pharos_native::runtime::json_commands::render_business_dashboard_empty_html("example");
11697/// ```
11698///
11699/// # Related
11700///
11701/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11702pub fn render_business_dashboard_empty_html(message: &str) -> String {
11703    html_escape_text(message)
11704}
11705
11706/// Builds a generated-surface filter control fragment from contract metadata.
11707///
11708/// # Parameters
11709///
11710/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_filter_controls_html`].
11711/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_filter_controls_html`].
11712/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_filter_controls_html`].
11713///
11714/// # Returns
11715///
11716/// Returns [`Some`] when [`crate::runtime::json_commands::build_generated_surface_filter_controls_html`] can produce a value and [`None`] otherwise.
11717///
11718/// # Examples
11719///
11720/// ```rust,ignore
11721/// let _result = pharos_native::runtime::json_commands::build_generated_surface_filter_controls_html(std::path::Path::new("apps/dev_docs"), "{}", todo!());
11722/// ```
11723///
11724/// # Related
11725///
11726/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11727pub fn build_generated_surface_filter_controls_html(
11728    app_root: &Path,
11729    surface_json: &str,
11730    raw_query: &str,
11731) -> Option<String> {
11732    generated_surface_filter_controls_html(app_root, surface_json, raw_query)
11733}
11734
11735/// Builds generated-surface form fields from contract metadata.
11736///
11737/// # Parameters
11738///
11739/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11740/// - `state_path`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11741/// - `fixture_path`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11742/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11743/// - `context_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11744/// - `item_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_form_fields_html`].
11745///
11746/// # Returns
11747///
11748/// Returns [`Some`] when [`crate::runtime::json_commands::build_generated_surface_form_fields_html`] can produce a value and [`None`] otherwise.
11749///
11750/// # Examples
11751///
11752/// ```rust,ignore
11753/// let _result = pharos_native::runtime::json_commands::build_generated_surface_form_fields_html(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), "{}", todo!(), "{}");
11754/// ```
11755///
11756/// # Related
11757///
11758/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11759pub fn build_generated_surface_form_fields_html(
11760    app_root: &Path,
11761    state_path: &Path,
11762    fixture_path: &Path,
11763    surface_json: &str,
11764    context_json: &str,
11765    item_json: Option<&str>,
11766) -> Option<String> {
11767    generated_surface_form_fields_html(
11768        app_root,
11769        state_path,
11770        fixture_path,
11771        surface_json,
11772        context_json,
11773        item_json,
11774    )
11775}
11776
11777/// Builds generated-surface sort options from contract metadata.
11778///
11779/// # Parameters
11780///
11781/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_sort_options_html`].
11782/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_sort_options_html`].
11783/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_sort_options_html`].
11784///
11785/// # Returns
11786///
11787/// Returns [`Some`] when [`crate::runtime::json_commands::build_generated_surface_sort_options_html`] can produce a value and [`None`] otherwise.
11788///
11789/// # Examples
11790///
11791/// ```rust,ignore
11792/// let _result = pharos_native::runtime::json_commands::build_generated_surface_sort_options_html(std::path::Path::new("apps/dev_docs"), "{}", todo!());
11793/// ```
11794///
11795/// # Related
11796///
11797/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11798pub fn build_generated_surface_sort_options_html(
11799    app_root: &Path,
11800    surface_json: &str,
11801    raw_query: &str,
11802) -> Option<String> {
11803    generated_surface_sort_options_html(app_root, surface_json, raw_query)
11804}
11805
11806/// Builds generated-surface management table parts from a bounded JSON value.
11807///
11808/// # Parameters
11809///
11810/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_manage_table_parts`].
11811/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_manage_table_parts`].
11812/// - `context_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_manage_table_parts`].
11813/// - `list_result_json`: Input consumed by [`crate::runtime::json_commands::build_generated_surface_manage_table_parts`].
11814///
11815/// # Returns
11816///
11817/// Returns [`Some`] when [`crate::runtime::json_commands::build_generated_surface_manage_table_parts`] can produce a value and [`None`] otherwise.
11818///
11819/// # Examples
11820///
11821/// ```rust,ignore
11822/// let _result = pharos_native::runtime::json_commands::build_generated_surface_manage_table_parts(std::path::Path::new("apps/dev_docs"), "{}", todo!(), todo!());
11823/// ```
11824///
11825/// # Related
11826///
11827/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11828pub fn build_generated_surface_manage_table_parts(
11829    app_root: &Path,
11830    surface_json: &str,
11831    context_json: &str,
11832    list_result_json: &str,
11833) -> Option<String> {
11834    generated_surface_manage_table_json(app_root, surface_json, context_json, list_result_json)
11835}
11836
11837/// Applies one generated-surface filter item to a record.
11838///
11839/// # Parameters
11840///
11841/// - `item`: Input consumed by [`crate::runtime::json_commands::surface_filter_item`].
11842/// - `filter`: Input consumed by [`crate::runtime::json_commands::surface_filter_item`].
11843/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::surface_filter_item`].
11844///
11845/// # Returns
11846///
11847/// Returns `true` when the condition checked by [`crate::runtime::json_commands::surface_filter_item`] holds and `false` otherwise.
11848///
11849/// # Examples
11850///
11851/// ```rust,ignore
11852/// let _result = pharos_native::runtime::json_commands::surface_filter_item(todo!(), todo!(), todo!());
11853/// ```
11854///
11855/// # Related
11856///
11857/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11858pub fn surface_filter_item(item: &Value, filter: &Value, raw_query: &str) -> bool {
11859    generated_surface_filter_matches(item, filter, raw_query)
11860}
11861
11862/// Builds active filter state from a raw query string.
11863///
11864/// # Parameters
11865///
11866/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::surface_build_active_filters`].
11867/// - `filters`: Input consumed by [`crate::runtime::json_commands::surface_build_active_filters`].
11868///
11869/// # Returns
11870///
11871/// Returns [`Some`] when [`crate::runtime::json_commands::surface_build_active_filters`] can produce a value and [`None`] otherwise.
11872///
11873/// # Performance
11874///
11875/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::surface_build_active_filters`].
11876///
11877/// # Examples
11878///
11879/// ```rust,ignore
11880/// let _result = pharos_native::runtime::json_commands::surface_build_active_filters(todo!(), todo!());
11881/// ```
11882///
11883/// # Related
11884///
11885/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11886pub fn surface_build_active_filters(raw_query: &str, filters: &Value) -> Option<String> {
11887    let mut active = Map::new();
11888    for filter in filters.as_array()? {
11889        let key = filter.get("field").and_then(Value::as_str)?;
11890        if let Some(value) = request_query_value(raw_query, key) {
11891            active.insert(key.to_owned(), Value::String(value));
11892        }
11893    }
11894    compact(&Value::Object(active))
11895}
11896
11897/// Builds stable sort configuration from a JSON contract and query string.
11898///
11899/// # Parameters
11900///
11901/// - `options`: Input consumed by [`crate::runtime::json_commands::surface_build_sort_config`].
11902/// - `raw_query`: Input consumed by [`crate::runtime::json_commands::surface_build_sort_config`].
11903///
11904/// # Returns
11905///
11906/// Returns [`Some`] when [`crate::runtime::json_commands::surface_build_sort_config`] can produce a value and [`None`] otherwise.
11907///
11908/// # Examples
11909///
11910/// ```rust,ignore
11911/// let _result = pharos_native::runtime::json_commands::surface_build_sort_config(todo!(), todo!());
11912/// ```
11913///
11914/// # Related
11915///
11916/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11917pub fn surface_build_sort_config(options: &Value, raw_query: &str) -> Option<String> {
11918    let field = request_query_value(raw_query, "sort").or_else(|| {
11919        options
11920            .get("default")
11921            .and_then(Value::as_str)
11922            .map(ToOwned::to_owned)
11923    });
11924    compact(
11925        &serde_json::json!({"field": field, "direction": request_query_value(raw_query, "direction").unwrap_or_else(|| "asc".to_owned())}),
11926    )
11927}
11928
11929/// Sorts a bounded list using a declared string or numeric field.
11930///
11931/// # Parameters
11932///
11933/// - `items`: Input consumed by [`crate::runtime::json_commands::surface_sort_items`].
11934/// - `field`: Input consumed by [`crate::runtime::json_commands::surface_sort_items`].
11935/// - `descending`: Input consumed by [`crate::runtime::json_commands::surface_sort_items`].
11936///
11937/// # Returns
11938///
11939/// Returns `true` when the condition checked by [`crate::runtime::json_commands::surface_sort_items`] holds and `false` otherwise.
11940///
11941/// # Examples
11942///
11943/// ```rust,ignore
11944/// let _result = pharos_native::runtime::json_commands::surface_sort_items(todo!(), "field", todo!());
11945/// ```
11946///
11947/// # Related
11948///
11949/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11950pub fn surface_sort_items(items: &mut Value, field: &str, descending: bool) -> bool {
11951    let Some(values) = items.as_array_mut() else {
11952        return false;
11953    };
11954    values.sort_by(|left, right| {
11955        let ordering = match (left.get(field), right.get(field)) {
11956            (Some(Value::Number(left)), Some(Value::Number(right))) => left
11957                .as_f64()
11958                .partial_cmp(&right.as_f64())
11959                .unwrap_or(std::cmp::Ordering::Equal),
11960            _ => value_to_text(left.get(field).unwrap_or(&Value::Null))
11961                .cmp(&value_to_text(right.get(field).unwrap_or(&Value::Null))),
11962        };
11963        if descending {
11964            ordering.reverse()
11965        } else {
11966            ordering
11967        }
11968    });
11969    true
11970}
11971
11972/// Finds an element in a UI ledger by its stable element id.
11973///
11974/// # Parameters
11975///
11976/// - `root`: Input consumed by [`crate::runtime::json_commands::find_ui_ledger_element`].
11977/// - `element_id`: Input consumed by [`crate::runtime::json_commands::find_ui_ledger_element`].
11978///
11979/// # Returns
11980///
11981/// Returns [`Some`] when [`crate::runtime::json_commands::find_ui_ledger_element`] can produce a value and [`None`] otherwise.
11982///
11983/// # Performance
11984///
11985/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_ui_ledger_element`].
11986///
11987/// # Examples
11988///
11989/// ```rust,ignore
11990/// let _result = pharos_native::runtime::json_commands::find_ui_ledger_element(std::path::Path::new("."), todo!());
11991/// ```
11992///
11993/// # Related
11994///
11995/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
11996pub fn find_ui_ledger_element(root: &Value, element_id: &str) -> Option<String> {
11997    let elements = root.get("elements").and_then(Value::as_array)?;
11998    elements
11999        .iter()
12000        .find(|item| item.get("id").and_then(Value::as_str) == Some(element_id))
12001        .and_then(compact)
12002}
12003
12004/// Performs business by slug.
12005fn business_by_slug<'a>(root: &'a Value, slug: &str) -> Option<&'a Value> {
12006    bounded_state_array(root, "businesses")
12007        .iter()
12008        .find(|business| business.get("slug").and_then(Value::as_str) == Some(slug))
12009}
12010
12011/// Emits the business edit-page JSON contract.
12012///
12013/// # Parameters
12014///
12015/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_edit_page`].
12016/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_business_edit_page`].
12017/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_business_edit_page`].
12018///
12019/// # Returns
12020///
12021/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_edit_page`] can produce a value and [`None`] otherwise.
12022///
12023/// # Examples
12024///
12025/// ```rust,ignore
12026/// let _result = pharos_native::runtime::json_commands::emit_business_edit_page(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"));
12027/// ```
12028///
12029/// # Related
12030///
12031/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12032pub fn emit_business_edit_page(root: &Value, slug: &str, app_root: &Path) -> Option<String> {
12033    let _ = app_root;
12034    let business = business_by_slug(root, slug)?;
12035    compact(&serde_json::json!({"business": business, "mode": "edit"}))
12036}
12037
12038/// Emits the public business page JSON contract.
12039///
12040/// # Parameters
12041///
12042/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_public_page`].
12043/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_business_public_page`].
12044/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_business_public_page`].
12045///
12046/// # Returns
12047///
12048/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_public_page`] can produce a value and [`None`] otherwise.
12049///
12050/// # Performance
12051///
12052/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_business_public_page`].
12053///
12054/// # Examples
12055///
12056/// ```rust,ignore
12057/// let _result = pharos_native::runtime::json_commands::emit_business_public_page(std::path::Path::new("."), todo!(), 1);
12058/// ```
12059///
12060/// # Related
12061///
12062/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12063pub fn emit_business_public_page(root: &Value, slug: &str, user_id: i64) -> Option<String> {
12064    let business = business_by_slug(root, slug)?;
12065    let business_id = business.get("id").and_then(Value::as_i64).unwrap_or(0);
12066    let services: Vec<Value> = bounded_state_array(root, "services")
12067        .iter()
12068        .filter(|service| service.get("business_id").and_then(Value::as_i64) == Some(business_id))
12069        .take(MAX_OUTPUT_ROWS_JSON)
12070        .cloned()
12071        .collect();
12072    let subscribed = bounded_state_array(root, "subscriptions")
12073        .iter()
12074        .any(|row| {
12075            row.get("business_id").and_then(Value::as_i64) == Some(business_id)
12076                && row.get("user_id").and_then(Value::as_i64) == Some(user_id)
12077        });
12078    compact(
12079        &serde_json::json!({"business": business, "services": services, "subscribed": subscribed}),
12080    )
12081}
12082
12083/// Emits service rows for a business administration page.
12084///
12085/// # Parameters
12086///
12087/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_service_rows`].
12088/// - `business_id`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_service_rows`].
12089///
12090/// # Returns
12091///
12092/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_admin_service_rows`] can produce a value and [`None`] otherwise.
12093///
12094/// # Examples
12095///
12096/// ```rust,ignore
12097/// let _result = pharos_native::runtime::json_commands::emit_business_admin_service_rows(std::path::Path::new("."), todo!());
12098/// ```
12099///
12100/// # Related
12101///
12102/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12103pub fn emit_business_admin_service_rows(root: &Value, business_id: i64) -> Option<String> {
12104    rows_as_json(root, "services", |row| {
12105        row.get("business_id").and_then(Value::as_i64) == Some(business_id)
12106    })
12107}
12108
12109/// Emits technician rows for a business administration page.
12110///
12111/// # Parameters
12112///
12113/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_technician_rows`].
12114/// - `business_id`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_technician_rows`].
12115///
12116/// # Returns
12117///
12118/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_admin_technician_rows`] can produce a value and [`None`] otherwise.
12119///
12120/// # Examples
12121///
12122/// ```rust,ignore
12123/// let _result = pharos_native::runtime::json_commands::emit_business_admin_technician_rows(std::path::Path::new("."), todo!());
12124/// ```
12125///
12126/// # Related
12127///
12128/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12129pub fn emit_business_admin_technician_rows(root: &Value, business_id: i64) -> Option<String> {
12130    rows_as_json(root, "technicians", |row| {
12131        row.get("business_id").and_then(Value::as_i64) == Some(business_id)
12132    })
12133}
12134
12135/// Emits the business calendar page contract.
12136///
12137/// # Parameters
12138///
12139/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_page`].
12140/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_page`].
12141///
12142/// # Returns
12143///
12144/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_calendar_page`] can produce a value and [`None`] otherwise.
12145///
12146/// # Performance
12147///
12148/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_business_calendar_page`].
12149///
12150/// # Examples
12151///
12152/// ```rust,ignore
12153/// let _result = pharos_native::runtime::json_commands::emit_business_calendar_page(std::path::Path::new("."), todo!());
12154/// ```
12155///
12156/// # Related
12157///
12158/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12159pub fn emit_business_calendar_page(root: &Value, slug: &str) -> Option<String> {
12160    let business = business_by_slug(root, slug)?;
12161    let business_id = business.get("id").and_then(Value::as_i64).unwrap_or(0);
12162    let availability: Vec<Value> = bounded_state_array(root, "business_availability")
12163        .iter()
12164        .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
12165        .take(MAX_OUTPUT_ROWS_JSON)
12166        .cloned()
12167        .collect();
12168    compact(&serde_json::json!({"business": business, "availability": availability}))
12169}
12170
12171/// Emits the rendered business-calendar page contract.
12172///
12173/// # Parameters
12174///
12175/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12176/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12177/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12178/// - `selected_year`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12179/// - `selected_month`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12180/// - `selected_date`: Input consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12181///
12182/// # Returns
12183///
12184/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_calendar_render_page`] can produce a value and [`None`] otherwise.
12185///
12186/// # Performance
12187///
12188/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_business_calendar_render_page`].
12189///
12190/// # Examples
12191///
12192/// ```rust,ignore
12193/// let _result = pharos_native::runtime::json_commands::emit_business_calendar_render_page(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
12194/// ```
12195///
12196/// # Related
12197///
12198/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12199pub fn emit_business_calendar_render_page(
12200    root: &Value,
12201    business_slug: &str,
12202    app_root: &Path,
12203    selected_year: Option<&str>,
12204    selected_month: Option<&str>,
12205    selected_date: Option<&str>,
12206) -> Option<String> {
12207    let _ = app_root;
12208    let page = emit_business_calendar_page(root, business_slug)?;
12209    let page = serde_json::from_str::<Value>(&page).ok()?;
12210    compact(&serde_json::json!({
12211        "page": page,
12212        "selected_year": selected_year,
12213        "selected_month": selected_month,
12214        "selected_date": selected_date,
12215    }))
12216}
12217
12218/// Emits the business public page with its render context.
12219///
12220/// # Parameters
12221///
12222/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_public_render_page`].
12223/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_business_public_render_page`].
12224/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_business_public_render_page`].
12225/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_business_public_render_page`].
12226///
12227/// # Returns
12228///
12229/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_public_render_page`] can produce a value and [`None`] otherwise.
12230///
12231/// # Performance
12232///
12233/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_business_public_render_page`].
12234///
12235/// # Examples
12236///
12237/// ```rust,ignore
12238/// let _result = pharos_native::runtime::json_commands::emit_business_public_render_page(std::path::Path::new("."), todo!(), 1, std::path::Path::new("apps/dev_docs"));
12239/// ```
12240///
12241/// # Related
12242///
12243/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12244pub fn emit_business_public_render_page(
12245    root: &Value,
12246    slug: &str,
12247    user_id: i64,
12248    app_root: &Path,
12249) -> Option<String> {
12250    let _ = app_root;
12251    let page = emit_business_public_page(root, slug, user_id)?;
12252    compact(&serde_json::json!({"page": serde_json::from_str::<Value>(&page).ok()?}))
12253}
12254
12255/// Emits a business dashboard page scoped to tenant identifiers.
12256///
12257/// # Parameters
12258///
12259/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_dashboard_page`].
12260/// - `tenant_ids`: Input consumed by [`crate::runtime::json_commands::emit_business_dashboard_page`].
12261/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_business_dashboard_page`].
12262///
12263/// # Returns
12264///
12265/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_dashboard_page`] can produce a value and [`None`] otherwise.
12266///
12267/// # Performance
12268///
12269/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_business_dashboard_page`].
12270///
12271/// # Examples
12272///
12273/// ```rust,ignore
12274/// let _result = pharos_native::runtime::json_commands::emit_business_dashboard_page(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"));
12275/// ```
12276///
12277/// # Related
12278///
12279/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12280pub fn emit_business_dashboard_page(
12281    root: &Value,
12282    tenant_ids: &Value,
12283    app_root: &Path,
12284) -> Option<String> {
12285    let _ = app_root;
12286    let businesses: Vec<Value> = bounded_state_array(root, "businesses")
12287        .iter()
12288        .filter(|business| {
12289            let id = business.get("id").and_then(Value::as_i64).unwrap_or(0);
12290            tenant_ids
12291                .as_array()
12292                .is_none_or(|ids| ids.iter().any(|item| item.as_i64() == Some(id)))
12293        })
12294        .take(MAX_OUTPUT_ROWS_JSON)
12295        .cloned()
12296        .collect();
12297    compact(&serde_json::json!({"businesses": businesses}))
12298}
12299
12300/// Emits the business administration page contract.
12301///
12302/// # Parameters
12303///
12304/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_page`].
12305/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_page`].
12306/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_page`].
12307/// - `invite_account_type_options_html`: Input consumed by [`crate::runtime::json_commands::emit_business_admin_page`].
12308///
12309/// # Returns
12310///
12311/// Returns [`Some`] when [`crate::runtime::json_commands::emit_business_admin_page`] can produce a value and [`None`] otherwise.
12312///
12313/// # Examples
12314///
12315/// ```rust,ignore
12316/// let _result = pharos_native::runtime::json_commands::emit_business_admin_page(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"), todo!());
12317/// ```
12318///
12319/// # Related
12320///
12321/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12322pub fn emit_business_admin_page(
12323    root: &Value,
12324    slug: &str,
12325    app_root: &Path,
12326    invite_account_type_options_html: Option<&str>,
12327) -> Option<String> {
12328    let _ = app_root;
12329    let business = business_by_slug(root, slug)?;
12330    compact(
12331        &serde_json::json!({"business": business, "invite_account_type_options_html": invite_account_type_options_html.unwrap_or_default()}),
12332    )
12333}
12334
12335/// Builds explore-page parameters from the public business collection.
12336///
12337/// # Parameters
12338///
12339/// - `root`: Input consumed by [`crate::runtime::json_commands::build_explore_page_params`].
12340/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_explore_page_params`].
12341///
12342/// # Returns
12343///
12344/// Returns [`Some`] when [`crate::runtime::json_commands::build_explore_page_params`] can produce a value and [`None`] otherwise.
12345///
12346/// # Examples
12347///
12348/// ```rust,ignore
12349/// let _result = pharos_native::runtime::json_commands::build_explore_page_params(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"));
12350/// ```
12351///
12352/// # Related
12353///
12354/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12355pub fn build_explore_page_params(root: &Value, app_root: &Path) -> Option<String> {
12356    let _ = app_root;
12357    emit_public_business_cards(root)
12358}
12359
12360/// Emits the explore page contract.
12361///
12362/// # Parameters
12363///
12364/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_explore_page`].
12365/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_explore_page`].
12366///
12367/// # Returns
12368///
12369/// Returns [`Some`] when [`crate::runtime::json_commands::emit_explore_page`] can produce a value and [`None`] otherwise.
12370///
12371/// # Examples
12372///
12373/// ```rust,ignore
12374/// let _result = pharos_native::runtime::json_commands::emit_explore_page(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"));
12375/// ```
12376///
12377/// # Related
12378///
12379/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12380pub fn emit_explore_page(root: &Value, app_root: &Path) -> Option<String> {
12381    build_explore_page_params(root, app_root)
12382}
12383
12384/// Emits a rendered profile page for one user.
12385///
12386/// # Parameters
12387///
12388/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_profile_page`].
12389/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_profile_page`].
12390///
12391/// # Returns
12392///
12393/// Returns [`Some`] when [`crate::runtime::json_commands::emit_profile_page`] can produce a value and [`None`] otherwise.
12394///
12395/// # Performance
12396///
12397/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_profile_page`].
12398///
12399/// # Examples
12400///
12401/// ```rust,ignore
12402/// let _result = pharos_native::runtime::json_commands::emit_profile_page(std::path::Path::new("."), 1);
12403/// ```
12404///
12405/// # Related
12406///
12407/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12408pub fn emit_profile_page(root: &Value, user_id: i64) -> Option<String> {
12409    let user = bounded_state_array(root, "users")
12410        .iter()
12411        .find(|row| row.get("id").and_then(Value::as_i64) == Some(user_id))?;
12412    compact(&serde_json::json!({"user": user}))
12413}
12414
12415/// Emits profile-page render context.
12416///
12417/// # Parameters
12418///
12419/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_profile_render_page`].
12420/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_profile_render_page`].
12421/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_profile_render_page`].
12422///
12423/// # Returns
12424///
12425/// Returns [`Some`] when [`crate::runtime::json_commands::emit_profile_render_page`] can produce a value and [`None`] otherwise.
12426///
12427/// # Examples
12428///
12429/// ```rust,ignore
12430/// let _result = pharos_native::runtime::json_commands::emit_profile_render_page(std::path::Path::new("."), 1, std::path::Path::new("apps/dev_docs"));
12431/// ```
12432///
12433/// # Related
12434///
12435/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12436pub fn emit_profile_render_page(root: &Value, user_id: i64, app_root: &Path) -> Option<String> {
12437    let _ = app_root;
12438    emit_profile_page(root, user_id)
12439}
12440
12441/// Emits appointments visible to a user and selected tenant ids.
12442///
12443/// # Parameters
12444///
12445/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_appointments_page`].
12446/// - `user_id`: Input consumed by [`crate::runtime::json_commands::emit_appointments_page`].
12447/// - `tenant_ids`: Input consumed by [`crate::runtime::json_commands::emit_appointments_page`].
12448/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_appointments_page`].
12449///
12450/// # Returns
12451///
12452/// Returns [`Some`] when [`crate::runtime::json_commands::emit_appointments_page`] can produce a value and [`None`] otherwise.
12453///
12454/// # Performance
12455///
12456/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_appointments_page`].
12457///
12458/// # Examples
12459///
12460/// ```rust,ignore
12461/// let _result = pharos_native::runtime::json_commands::emit_appointments_page(std::path::Path::new("."), 1, todo!(), std::path::Path::new("apps/dev_docs"));
12462/// ```
12463///
12464/// # Related
12465///
12466/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12467pub fn emit_appointments_page(
12468    root: &Value,
12469    user_id: i64,
12470    tenant_ids: &Value,
12471    app_root: &Path,
12472) -> Option<String> {
12473    let _ = app_root;
12474    let appointments: Vec<Value> = bounded_state_array(root, "appointments")
12475        .iter()
12476        .filter(|row| row.get("user_id").and_then(Value::as_i64) == Some(user_id))
12477        .filter(|row| {
12478            tenant_ids.as_array().is_none_or(|ids| {
12479                ids.iter()
12480                    .any(|item| item.as_i64() == row.get("tenant_id").and_then(Value::as_i64))
12481            })
12482        })
12483        .take(MAX_OUTPUT_ROWS_JSON)
12484        .cloned()
12485        .collect();
12486    compact(&Value::Array(appointments))
12487}
12488
12489/// Emits the service booking form contract.
12490///
12491/// # Parameters
12492///
12493/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12494/// - `slug`: Input consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12495/// - `service_id`: Input consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12496/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12497/// - `error_message`: Input consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12498///
12499/// # Returns
12500///
12501/// Returns [`Some`] when [`crate::runtime::json_commands::emit_service_book_form_page`] can produce a value and [`None`] otherwise.
12502///
12503/// # Performance
12504///
12505/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_service_book_form_page`].
12506///
12507/// # Examples
12508///
12509/// ```rust,ignore
12510/// let _result = pharos_native::runtime::json_commands::emit_service_book_form_page(std::path::Path::new("."), todo!(), todo!(), std::path::Path::new("apps/dev_docs"), todo!());
12511/// ```
12512///
12513/// # Related
12514///
12515/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12516pub fn emit_service_book_form_page(
12517    root: &Value,
12518    slug: &str,
12519    service_id: i64,
12520    app_root: &Path,
12521    error_message: Option<&str>,
12522) -> Option<String> {
12523    let _ = app_root;
12524    let service = bounded_state_array(root, "services").iter().find(|row| {
12525        row.get("id").and_then(Value::as_i64) == Some(service_id)
12526            && business_by_slug(root, slug).is_some()
12527    })?;
12528    compact(
12529        &serde_json::json!({"service": service, "error_message": error_message.unwrap_or_default()}),
12530    )
12531}
12532
12533/// Emits the service-edit page contract.
12534///
12535/// # Parameters
12536///
12537/// - `root`: Input consumed by [`crate::runtime::json_commands::emit_service_edit_page`].
12538/// - `service_id`: Input consumed by [`crate::runtime::json_commands::emit_service_edit_page`].
12539/// - `app_root`: Input consumed by [`crate::runtime::json_commands::emit_service_edit_page`].
12540///
12541/// # Returns
12542///
12543/// Returns [`Some`] when [`crate::runtime::json_commands::emit_service_edit_page`] can produce a value and [`None`] otherwise.
12544///
12545/// # Performance
12546///
12547/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::emit_service_edit_page`].
12548///
12549/// # Examples
12550///
12551/// ```rust,ignore
12552/// let _result = pharos_native::runtime::json_commands::emit_service_edit_page(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"));
12553/// ```
12554///
12555/// # Related
12556///
12557/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12558pub fn emit_service_edit_page(root: &Value, service_id: i64, app_root: &Path) -> Option<String> {
12559    let _ = app_root;
12560    let service = bounded_state_array(root, "services")
12561        .iter()
12562        .find(|row| row.get("id").and_then(Value::as_i64) == Some(service_id))?;
12563    compact(&serde_json::json!({"service": service, "mode": "edit"}))
12564}
12565
12566/// Records one pair in a bounded seen-pair set and reports whether it was new.
12567///
12568/// # Parameters
12569///
12570/// - `seen`: Input consumed by [`crate::runtime::json_commands::seen_long_pair`].
12571/// - `left`: Input consumed by [`crate::runtime::json_commands::seen_long_pair`].
12572/// - `right`: Input consumed by [`crate::runtime::json_commands::seen_long_pair`].
12573///
12574/// # Returns
12575///
12576/// Returns `true` when the condition checked by [`crate::runtime::json_commands::seen_long_pair`] holds and `false` otherwise.
12577///
12578/// # Examples
12579///
12580/// ```rust,ignore
12581/// let _result = pharos_native::runtime::json_commands::seen_long_pair(todo!(), todo!(), todo!());
12582/// ```
12583///
12584/// # Related
12585///
12586/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12587pub fn seen_long_pair(seen: &mut Vec<(i64, i64)>, left: i64, right: i64) -> bool {
12588    if seen.contains(&(left, right)) {
12589        return false;
12590    }
12591    if seen.len() >= MAX_OUTPUT_ROWS_JSON {
12592        return false;
12593    }
12594    seen.push((left, right));
12595    true
12596}
12597
12598/// Converts one event row into the safe Rust event-stream representation.
12599///
12600/// # Parameters
12601///
12602/// - `row`: Input consumed by [`crate::runtime::json_commands::collect_event_stream_row`].
12603/// - `native_order`: Input consumed by [`crate::runtime::json_commands::collect_event_stream_row`].
12604///
12605/// # Returns
12606///
12607/// Returns [`Some`] when [`crate::runtime::json_commands::collect_event_stream_row`] can produce a value and [`None`] otherwise.
12608///
12609/// # Examples
12610///
12611/// ```rust,ignore
12612/// let _result = pharos_native::runtime::json_commands::collect_event_stream_row(todo!(), todo!());
12613/// ```
12614///
12615/// # Related
12616///
12617/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12618pub fn collect_event_stream_row(
12619    row: &Value,
12620    native_order: i64,
12621) -> Option<super::json_ops::EventStreamRowRuntime> {
12622    row.is_object()
12623        .then(|| super::json_ops::EventStreamRowRuntime {
12624            created_at: row
12625                .get("created_at")
12626                .and_then(Value::as_str)
12627                .map(ToOwned::to_owned),
12628            source: row
12629                .get("source")
12630                .and_then(Value::as_str)
12631                .map(ToOwned::to_owned),
12632            native_order,
12633        })
12634}
12635
12636/// Releases all event rows owned by a caller.
12637///
12638/// # Parameters
12639///
12640/// - `rows`: Input consumed by [`crate::runtime::json_commands::free_event_stream_row_list`].
12641///
12642/// # Returns
12643///
12644/// Returns after [`crate::runtime::json_commands::free_event_stream_row_list`] applies its in-place effect.
12645///
12646/// # Examples
12647///
12648/// ```rust,ignore
12649/// let _result = pharos_native::runtime::json_commands::free_event_stream_row_list(todo!());
12650/// ```
12651///
12652/// # Related
12653///
12654/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12655pub fn free_event_stream_row_list(rows: &mut Vec<super::json_ops::EventStreamRowRuntime>) {
12656    rows.clear();
12657}
12658
12659/// Appends one event-stream row to a bounded JSON array.
12660///
12661/// # Parameters
12662///
12663/// - `output`: Input consumed by [`crate::runtime::json_commands::append_event_stream_row`].
12664/// - `row`: Input consumed by [`crate::runtime::json_commands::append_event_stream_row`].
12665///
12666/// # Returns
12667///
12668/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_event_stream_row`] holds and `false` otherwise.
12669///
12670/// # Examples
12671///
12672/// ```rust,ignore
12673/// let _result = pharos_native::runtime::json_commands::append_event_stream_row(todo!(), todo!());
12674/// ```
12675///
12676/// # Related
12677///
12678/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12679pub fn append_event_stream_row(output: &mut Vec<Value>, row: &Value) -> bool {
12680    if output.len() >= MAX_OUTPUT_ROWS_JSON || !row.is_object() {
12681        return false;
12682    }
12683    output.push(row.clone());
12684    true
12685}
12686
12687/// Appends relation checkbox HTML using the app-owned generated fragment contract.
12688///
12689/// # Parameters
12690///
12691/// - `output`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12692/// - `app_root`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12693/// - `state_path`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12694/// - `relation_json`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12695/// - `context_json`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12696/// - `selected_json`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`].
12697///
12698/// # Returns
12699///
12700/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_generated_surface_relation_checkboxes_html`] holds and `false` otherwise.
12701///
12702/// # Examples
12703///
12704/// ```rust,ignore
12705/// let _result = pharos_native::runtime::json_commands::append_generated_surface_relation_checkboxes_html(todo!(), std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
12706/// ```
12707///
12708/// # Related
12709///
12710/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12711pub fn append_generated_surface_relation_checkboxes_html(
12712    output: &mut String,
12713    app_root: &Path,
12714    state_path: &Path,
12715    relation_json: &str,
12716    context_json: &str,
12717    selected_json: Option<&str>,
12718) -> bool {
12719    let Some(fragment) = generated_surface_relation_checkboxes_html(
12720        app_root,
12721        state_path,
12722        relation_json,
12723        context_json,
12724        selected_json,
12725    ) else {
12726        return false;
12727    };
12728    if output.len().saturating_add(fragment.len()) > MAX_TEXT_BYTES {
12729        return false;
12730    }
12731    output.push_str(&fragment);
12732    true
12733}
12734
12735/// Appends generated select options using the app-owned fragment contract.
12736///
12737/// # Parameters
12738///
12739/// - `output`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_select_options_html`].
12740/// - `app_root`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_select_options_html`].
12741/// - `field_json`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_select_options_html`].
12742/// - `selected`: Input consumed by [`crate::runtime::json_commands::append_generated_surface_select_options_html`].
12743///
12744/// # Returns
12745///
12746/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_generated_surface_select_options_html`] holds and `false` otherwise.
12747///
12748/// # Examples
12749///
12750/// ```rust,ignore
12751/// let _result = pharos_native::runtime::json_commands::append_generated_surface_select_options_html(todo!(), std::path::Path::new("apps/dev_docs"), todo!(), todo!());
12752/// ```
12753///
12754/// # Related
12755///
12756/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12757pub fn append_generated_surface_select_options_html(
12758    output: &mut String,
12759    app_root: &Path,
12760    field_json: &str,
12761    selected: Option<&str>,
12762) -> bool {
12763    let Some(fragment) = generated_surface_select_options_html(app_root, field_json, selected)
12764    else {
12765        return false;
12766    };
12767    if output.len().saturating_add(fragment.len()) > MAX_TEXT_BYTES {
12768        return false;
12769    }
12770    output.push_str(&fragment);
12771    true
12772}
12773
12774/// Performs a bounded case-insensitive substring test.
12775///
12776/// # Parameters
12777///
12778/// - `haystack`: Input consumed by [`crate::runtime::json_commands::contains_casefold`].
12779/// - `needle`: Input consumed by [`crate::runtime::json_commands::contains_casefold`].
12780///
12781/// # Returns
12782///
12783/// Returns `true` when the condition checked by [`crate::runtime::json_commands::contains_casefold`] holds and `false` otherwise.
12784///
12785/// # Examples
12786///
12787/// ```rust,ignore
12788/// let _result = pharos_native::runtime::json_commands::contains_casefold(todo!(), todo!());
12789/// ```
12790///
12791/// # Related
12792///
12793/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12794pub fn contains_casefold(haystack: &str, needle: &str) -> bool {
12795    !needle.is_empty()
12796        && haystack
12797            .to_ascii_lowercase()
12798            .contains(&needle.to_ascii_lowercase())
12799}
12800
12801/// Returns whether text is non-empty ASCII decimal digits.
12802///
12803/// # Parameters
12804///
12805/// - `text`: Input consumed by [`crate::runtime::json_commands::is_nonempty_ascii_digits`].
12806///
12807/// # Returns
12808///
12809/// Returns `true` when the condition checked by [`crate::runtime::json_commands::is_nonempty_ascii_digits`] holds and `false` otherwise.
12810///
12811/// # Performance
12812///
12813/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::is_nonempty_ascii_digits`].
12814///
12815/// # Examples
12816///
12817/// ```rust,ignore
12818/// let _result = pharos_native::runtime::json_commands::is_nonempty_ascii_digits("{}");
12819/// ```
12820///
12821/// # Related
12822///
12823/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12824pub fn is_nonempty_ascii_digits(text: &str) -> bool {
12825    !text.is_empty() && text.bytes().all(|byte| byte.is_ascii_digit())
12826}
12827
12828/// Returns an owned non-empty value or the supplied default.
12829///
12830/// # Parameters
12831///
12832/// - `value`: Input consumed by [`crate::runtime::json_commands::dup_or_default`].
12833/// - `default_value`: Input consumed by [`crate::runtime::json_commands::dup_or_default`].
12834///
12835/// # Returns
12836///
12837/// Returns the computed value produced by [`crate::runtime::json_commands::dup_or_default`].
12838///
12839/// # Examples
12840///
12841/// ```rust,ignore
12842/// let _result = pharos_native::runtime::json_commands::dup_or_default("value", todo!());
12843/// ```
12844///
12845/// # Related
12846///
12847/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12848pub fn dup_or_default(value: Option<&str>, default_value: &str) -> String {
12849    value
12850        .filter(|value| !value.is_empty())
12851        .unwrap_or(default_value)
12852        .to_owned()
12853}
12854
12855/// Emits a compact mutable JSON value and retains the caller's mutation ownership.
12856///
12857/// # Parameters
12858///
12859/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_compact_json_mut_value`].
12860///
12861/// # Returns
12862///
12863/// Returns [`Some`] when [`crate::runtime::json_commands::emit_compact_json_mut_value`] can produce a value and [`None`] otherwise.
12864///
12865/// # Examples
12866///
12867/// ```rust,ignore
12868/// let _result = pharos_native::runtime::json_commands::emit_compact_json_mut_value("value");
12869/// ```
12870///
12871/// # Related
12872///
12873/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12874pub fn emit_compact_json_mut_value(value: &mut Value) -> Option<String> {
12875    compact(value)
12876}
12877
12878/// Emits one compact JSON value followed by a newline.
12879///
12880/// # Parameters
12881///
12882/// - `value`: Input consumed by [`crate::runtime::json_commands::emit_json_line`].
12883///
12884/// # Returns
12885///
12886/// Returns [`Some`] when [`crate::runtime::json_commands::emit_json_line`] can produce a value and [`None`] otherwise.
12887///
12888/// # Examples
12889///
12890/// ```rust,ignore
12891/// let _result = pharos_native::runtime::json_commands::emit_json_line("value");
12892/// ```
12893///
12894/// # Related
12895///
12896/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12897pub fn emit_json_line(value: &Value) -> Option<String> {
12898    Some(format!("{}\n", compact(value)?))
12899}
12900
12901/// Checks whether one event row is visible within a user and tenant scope.
12902///
12903/// # Parameters
12904///
12905/// - `row`: Input consumed by [`crate::runtime::json_commands::event_stream_allowed_by_scope`].
12906/// - `user_id`: Input consumed by [`crate::runtime::json_commands::event_stream_allowed_by_scope`].
12907/// - `tenant_id`: Input consumed by [`crate::runtime::json_commands::event_stream_allowed_by_scope`].
12908///
12909/// # Returns
12910///
12911/// Returns `true` when the condition checked by [`crate::runtime::json_commands::event_stream_allowed_by_scope`] holds and `false` otherwise.
12912///
12913/// # Examples
12914///
12915/// ```rust,ignore
12916/// let _result = pharos_native::runtime::json_commands::event_stream_allowed_by_scope(todo!(), 1, todo!());
12917/// ```
12918///
12919/// # Related
12920///
12921/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12922pub fn event_stream_allowed_by_scope(row: &Value, user_id: i64, tenant_id: i64) -> bool {
12923    let row_user = row.get("user_id").and_then(Value::as_i64);
12924    let row_tenant = row.get("tenant_id").and_then(Value::as_i64);
12925    (row_user.is_none() || row_user == Some(user_id))
12926        && (row_tenant.is_none() || row_tenant == Some(tenant_id))
12927}
12928
12929/// Matches event-stream filters declared as a JSON object.
12930///
12931/// # Parameters
12932///
12933/// - `row`: Input consumed by [`crate::runtime::json_commands::event_stream_matches_filters`].
12934/// - `filters`: Input consumed by [`crate::runtime::json_commands::event_stream_matches_filters`].
12935///
12936/// # Returns
12937///
12938/// Returns `true` when the condition checked by [`crate::runtime::json_commands::event_stream_matches_filters`] holds and `false` otherwise.
12939///
12940/// # Performance
12941///
12942/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::event_stream_matches_filters`].
12943///
12944/// # Examples
12945///
12946/// ```rust,ignore
12947/// let _result = pharos_native::runtime::json_commands::event_stream_matches_filters(todo!(), todo!());
12948/// ```
12949///
12950/// # Related
12951///
12952/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12953pub fn event_stream_matches_filters(row: &Value, filters: &Value) -> bool {
12954    filters.as_object().is_none_or(|entries| {
12955        entries
12956            .iter()
12957            .all(|(key, expected)| row.get(key).is_some_and(|actual| actual == expected))
12958    })
12959}
12960
12961/// Returns a bounded event resource identifier.
12962///
12963/// # Parameters
12964///
12965/// - `row`: Input consumed by [`crate::runtime::json_commands::event_stream_resource_id`].
12966///
12967/// # Returns
12968///
12969/// Returns [`Some`] when [`crate::runtime::json_commands::event_stream_resource_id`] can produce a value and [`None`] otherwise.
12970///
12971/// # Examples
12972///
12973/// ```rust,ignore
12974/// let _result = pharos_native::runtime::json_commands::event_stream_resource_id(todo!());
12975/// ```
12976///
12977/// # Related
12978///
12979/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
12980pub fn event_stream_resource_id(row: &Value) -> Option<String> {
12981    row.get("resource_id")
12982        .or_else(|| row.get("id"))
12983        .map(value_to_text)
12984        .filter(|value| !value.is_empty())
12985}
12986
12987/// Returns a positive event tenant identifier.
12988///
12989/// # Parameters
12990///
12991/// - `row`: Input consumed by [`crate::runtime::json_commands::event_stream_tenant_id`].
12992///
12993/// # Returns
12994///
12995/// Returns the computed value produced by [`crate::runtime::json_commands::event_stream_tenant_id`].
12996///
12997/// # Examples
12998///
12999/// ```rust,ignore
13000/// let _result = pharos_native::runtime::json_commands::event_stream_tenant_id(todo!());
13001/// ```
13002///
13003/// # Related
13004///
13005/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13006pub fn event_stream_tenant_id(row: &Value) -> i64 {
13007    row.get("tenant_id")
13008        .and_then(Value::as_i64)
13009        .unwrap_or(0)
13010        .max(0)
13011}
13012
13013/// Finds an array row by a positive integer field.
13014///
13015/// # Parameters
13016///
13017/// - `root`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_long_field`].
13018/// - `section`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_long_field`].
13019/// - `field`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_long_field`].
13020/// - `wanted`: Input consumed by [`crate::runtime::json_commands::find_array_item_by_long_field`].
13021///
13022/// # Returns
13023///
13024/// Returns [`Some`] when [`crate::runtime::json_commands::find_array_item_by_long_field`] can produce a value and [`None`] otherwise.
13025///
13026/// # Performance
13027///
13028/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_array_item_by_long_field`].
13029///
13030/// # Examples
13031///
13032/// ```rust,ignore
13033/// let _result = pharos_native::runtime::json_commands::find_array_item_by_long_field(std::path::Path::new("."), "items", "field", todo!());
13034/// ```
13035///
13036/// # Related
13037///
13038/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13039pub fn find_array_item_by_long_field(
13040    root: &Value,
13041    section: &str,
13042    field: &str,
13043    wanted: i64,
13044) -> Option<String> {
13045    bounded_state_array(root, section)
13046        .iter()
13047        .find(|item| item.get(field).and_then(Value::as_i64) == Some(wanted))
13048        .and_then(compact)
13049}
13050
13051/// Releases one optional event-stream row.
13052///
13053/// # Parameters
13054///
13055/// - `row`: Input consumed by [`crate::runtime::json_commands::free_event_stream_row`].
13056///
13057/// # Returns
13058///
13059/// Returns after [`crate::runtime::json_commands::free_event_stream_row`] applies its in-place effect.
13060///
13061/// # Examples
13062///
13063/// ```rust,ignore
13064/// let _result = pharos_native::runtime::json_commands::free_event_stream_row(todo!());
13065/// ```
13066///
13067/// # Related
13068///
13069/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13070pub fn free_event_stream_row(row: &mut Option<super::json_ops::EventStreamRowRuntime>) {
13071    *row = None;
13072}
13073
13074/// Produces the canonical generated-surface label for one field.
13075///
13076/// # Parameters
13077///
13078/// - `field_name`: Input consumed by [`crate::runtime::json_commands::generated_surface_label_from_field`].
13079///
13080/// # Returns
13081///
13082/// Returns the computed value produced by [`crate::runtime::json_commands::generated_surface_label_from_field`].
13083///
13084/// # Examples
13085///
13086/// ```rust,ignore
13087/// let _result = pharos_native::runtime::json_commands::generated_surface_label_from_field(todo!());
13088/// ```
13089///
13090/// # Related
13091///
13092/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13093pub fn generated_surface_label_from_field(field_name: &str) -> String {
13094    super::dynamic::generated_surface_label(Some(field_name)).unwrap_or_default()
13095}
13096
13097/// Appends one JSON value to an owned list.
13098///
13099/// # Parameters
13100///
13101/// - `list`: Input consumed by [`crate::runtime::json_commands::json_value_list_append`].
13102/// - `value`: Input consumed by [`crate::runtime::json_commands::json_value_list_append`].
13103///
13104/// # Returns
13105///
13106/// Returns `true` when the condition checked by [`crate::runtime::json_commands::json_value_list_append`] holds and `false` otherwise.
13107///
13108/// # Examples
13109///
13110/// ```rust,ignore
13111/// let _result = pharos_native::runtime::json_commands::json_value_list_append(todo!(), "value");
13112/// ```
13113///
13114/// # Related
13115///
13116/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13117pub fn json_value_list_append(
13118    list: &mut super::dynamic::RuntimeJsonValueList,
13119    value: &Value,
13120) -> bool {
13121    super::dynamic::runtime_json_value_list_append(list, value)
13122}
13123
13124/// Frees all values from an owned JSON list.
13125///
13126/// # Parameters
13127///
13128/// - `list`: Input consumed by [`crate::runtime::json_commands::json_value_list_free`].
13129///
13130/// # Returns
13131///
13132/// Returns after [`crate::runtime::json_commands::json_value_list_free`] applies its in-place effect.
13133///
13134/// # Examples
13135///
13136/// ```rust,ignore
13137/// let _result = pharos_native::runtime::json_commands::json_value_list_free(todo!());
13138/// ```
13139///
13140/// # Related
13141///
13142/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13143pub fn json_value_list_free(list: &mut super::dynamic::RuntimeJsonValueList) {
13144    super::dynamic::runtime_json_value_list_free(list);
13145}
13146
13147/// Applies the native truthiness contract to a JSON value.
13148///
13149/// # Parameters
13150///
13151/// - `value`: Input consumed by [`crate::runtime::json_commands::json_value_truthy`].
13152///
13153/// # Returns
13154///
13155/// Returns `true` when the condition checked by [`crate::runtime::json_commands::json_value_truthy`] holds and `false` otherwise.
13156///
13157/// # Examples
13158///
13159/// ```rust,ignore
13160/// let _result = pharos_native::runtime::json_commands::json_value_truthy("value");
13161/// ```
13162///
13163/// # Related
13164///
13165/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13166pub fn json_value_truthy(value: &Value) -> bool {
13167    match value {
13168        Value::Null => false,
13169        Value::Bool(value) => *value,
13170        Value::Number(value) => {
13171            value.as_i64().is_some_and(|value| value != 0)
13172                || value.as_f64().is_some_and(|value| value != 0.0)
13173        }
13174        Value::String(value) => {
13175            !value.is_empty() && !matches!(value.as_str(), "0" | "false" | "off" | "no")
13176        }
13177        Value::Array(value) => !value.is_empty(),
13178        Value::Object(value) => !value.is_empty(),
13179    }
13180}
13181
13182/// Returns the first string value from a payload object or array.
13183///
13184/// # Parameters
13185///
13186/// - `value`: Input consumed by [`crate::runtime::json_commands::payload_first_string`].
13187///
13188/// # Returns
13189///
13190/// Returns [`Some`] when [`crate::runtime::json_commands::payload_first_string`] can produce a value and [`None`] otherwise.
13191///
13192/// # Performance
13193///
13194/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::payload_first_string`].
13195///
13196/// # Examples
13197///
13198/// ```rust,ignore
13199/// let _result = pharos_native::runtime::json_commands::payload_first_string("value");
13200/// ```
13201///
13202/// # Related
13203///
13204/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13205pub fn payload_first_string(value: &Value) -> Option<String> {
13206    match value {
13207        Value::String(value) if !value.is_empty() => Some(value.clone()),
13208        Value::Array(items) => items.iter().find_map(payload_first_string),
13209        Value::Object(object) => object.values().find_map(payload_first_string),
13210        _ => None,
13211    }
13212}
13213
13214/// Reads a content-disposition parameter using strict quoted-field parsing.
13215///
13216/// # Parameters
13217///
13218/// - `headers`: Input consumed by [`crate::runtime::json_commands::content_disposition_param`].
13219/// - `key`: Input consumed by [`crate::runtime::json_commands::content_disposition_param`].
13220///
13221/// # Returns
13222///
13223/// Returns [`Some`] when [`crate::runtime::json_commands::content_disposition_param`] can produce a value and [`None`] otherwise.
13224///
13225/// # Examples
13226///
13227/// ```rust,ignore
13228/// let _result = pharos_native::runtime::json_commands::content_disposition_param("host: example", "key");
13229/// ```
13230///
13231/// # Related
13232///
13233/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13234pub fn content_disposition_param(headers: &str, key: &str) -> Option<String> {
13235    multipart_header_param(headers, key)
13236}
13237
13238/// Returns the decoded value for one query key.
13239///
13240/// # Parameters
13241///
13242/// - `query`: Input consumed by [`crate::runtime::json_commands::query_value_decoded`].
13243/// - `key`: Input consumed by [`crate::runtime::json_commands::query_value_decoded`].
13244///
13245/// # Returns
13246///
13247/// Returns [`Some`] when [`crate::runtime::json_commands::query_value_decoded`] can produce a value and [`None`] otherwise.
13248///
13249/// # Examples
13250///
13251/// ```rust,ignore
13252/// let _result = pharos_native::runtime::json_commands::query_value_decoded("page=1", "key");
13253/// ```
13254///
13255/// # Related
13256///
13257/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13258pub fn query_value_decoded(query: &str, key: &str) -> Option<String> {
13259    request_query_value(query, key)
13260}
13261
13262/// Classifies a resource identifier by its stable prefix.
13263///
13264/// # Parameters
13265///
13266/// - `resource_id`: Input consumed by [`crate::runtime::json_commands::resource_kind_from_resource_id`].
13267///
13268/// # Returns
13269///
13270/// Returns [`Some`] when [`crate::runtime::json_commands::resource_kind_from_resource_id`] can produce a value and [`None`] otherwise.
13271///
13272/// # Performance
13273///
13274/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::resource_kind_from_resource_id`].
13275///
13276/// # Examples
13277///
13278/// ```rust,ignore
13279/// let _result = pharos_native::runtime::json_commands::resource_kind_from_resource_id(todo!());
13280/// ```
13281///
13282/// # Related
13283///
13284/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13285pub fn resource_kind_from_resource_id(resource_id: &str) -> Option<&'static str> {
13286    let prefix = resource_id.split(':').next()?;
13287    match prefix {
13288        "user" => Some("user"),
13289        "business" => Some("business"),
13290        "service" => Some("service"),
13291        "technician" => Some("technician"),
13292        "appointment" => Some("appointment"),
13293        "tenant" => Some("tenant"),
13294        _ => None,
13295    }
13296}
13297
13298/// Compares two surface values for stable sorting.
13299///
13300/// # Parameters
13301///
13302/// - `left`: Input consumed by [`crate::runtime::json_commands::surface_compare_sort_values`].
13303/// - `right`: Input consumed by [`crate::runtime::json_commands::surface_compare_sort_values`].
13304///
13305/// # Returns
13306///
13307/// Returns the computed value produced by [`crate::runtime::json_commands::surface_compare_sort_values`].
13308///
13309/// # Examples
13310///
13311/// ```rust,ignore
13312/// let _result = pharos_native::runtime::json_commands::surface_compare_sort_values(todo!(), todo!());
13313/// ```
13314///
13315/// # Related
13316///
13317/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13318pub fn surface_compare_sort_values(left: &Value, right: &Value) -> std::cmp::Ordering {
13319    value_to_text(left).cmp(&value_to_text(right))
13320}
13321
13322/// Finds one form declaration by its id.
13323///
13324/// # Parameters
13325///
13326/// - `root`: Input consumed by [`crate::runtime::json_commands::surface_find_form`].
13327/// - `form_id`: Input consumed by [`crate::runtime::json_commands::surface_find_form`].
13328///
13329/// # Returns
13330///
13331/// Returns [`Some`] when [`crate::runtime::json_commands::surface_find_form`] can produce a value and [`None`] otherwise.
13332///
13333/// # Performance
13334///
13335/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::surface_find_form`].
13336///
13337/// # Examples
13338///
13339/// ```rust,ignore
13340/// let _result = pharos_native::runtime::json_commands::surface_find_form(std::path::Path::new("."), "form");
13341/// ```
13342///
13343/// # Related
13344///
13345/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13346pub fn surface_find_form(root: &Value, form_id: &str) -> Option<String> {
13347    root.get("forms")?
13348        .as_array()?
13349        .iter()
13350        .find(|form| form.get("form_id").and_then(Value::as_str) == Some(form_id))
13351        .and_then(compact)
13352}
13353
13354/// Returns the first position of a byte needle in a bounded byte slice.
13355///
13356/// # Parameters
13357///
13358/// - `haystack`: Input consumed by [`crate::runtime::json_commands::memmem`].
13359/// - `needle`: Input consumed by [`crate::runtime::json_commands::memmem`].
13360///
13361/// # Returns
13362///
13363/// Returns [`Some`] when [`crate::runtime::json_commands::memmem`] can produce a value and [`None`] otherwise.
13364///
13365/// # Examples
13366///
13367/// ```rust,ignore
13368/// let _result = pharos_native::runtime::json_commands::memmem(todo!(), todo!());
13369/// ```
13370///
13371/// # Related
13372///
13373/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13374pub fn memmem(haystack: &[u8], needle: &[u8]) -> Option<usize> {
13375    if needle.is_empty() {
13376        return Some(0);
13377    }
13378    haystack
13379        .windows(needle.len())
13380        .position(|window| window == needle)
13381}
13382
13383/// Renders one generated-surface action link from an app-owned fragment.
13384///
13385/// # Parameters
13386///
13387/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_action_link`].
13388/// - `action_path`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_action_link`].
13389/// - `label`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_action_link`].
13390///
13391/// # Returns
13392///
13393/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_action_link`] can produce a value and [`None`] otherwise.
13394///
13395/// # Examples
13396///
13397/// ```rust,ignore
13398/// let _result = pharos_native::runtime::json_commands::render_generated_surface_action_link(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
13399/// ```
13400///
13401/// # Related
13402///
13403/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13404pub fn render_generated_surface_action_link(
13405    app_root: &Path,
13406    action_path: &str,
13407    label: &str,
13408) -> Option<String> {
13409    let params = Map::from_iter([
13410        (
13411            "action_path".to_owned(),
13412            Value::String(action_path.to_owned()),
13413        ),
13414        ("button_label".to_owned(), Value::String(label.to_owned())),
13415        (
13416            "button_class".to_owned(),
13417            Value::String("btn-secondary".to_owned()),
13418        ),
13419    ]);
13420    generated::render_generated_admin_fragment_from_value_runtime(
13421        app_root,
13422        "templates/shared/fragments/action_link.html",
13423        &params,
13424    )
13425}
13426
13427/// Renders one generated-surface delete form from a validated action path.
13428///
13429/// # Parameters
13430///
13431/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_delete_form`].
13432/// - `action_path`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_delete_form`].
13433/// - `label`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_delete_form`].
13434///
13435/// # Returns
13436///
13437/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_delete_form`] can produce a value and [`None`] otherwise.
13438///
13439/// # Examples
13440///
13441/// ```rust,ignore
13442/// let _result = pharos_native::runtime::json_commands::render_generated_surface_delete_form(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
13443/// ```
13444///
13445/// # Related
13446///
13447/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13448pub fn render_generated_surface_delete_form(
13449    app_root: &Path,
13450    action_path: &str,
13451    label: &str,
13452) -> Option<String> {
13453    let params = Map::from_iter([
13454        (
13455            "action_path".to_owned(),
13456            Value::String(action_path.to_owned()),
13457        ),
13458        ("button_label".to_owned(), Value::String(label.to_owned())),
13459    ]);
13460    generated::render_generated_admin_fragment_from_value_runtime(
13461        app_root,
13462        "templates/generated_admin/fragments/delete_form.html",
13463        &params,
13464    )
13465}
13466
13467/// Renders a generated-surface table header cell.
13468///
13469/// # Parameters
13470///
13471/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_header_cell`].
13472/// - `label`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_header_cell`].
13473///
13474/// # Returns
13475///
13476/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_table_header_cell`] can produce a value and [`None`] otherwise.
13477///
13478/// # Examples
13479///
13480/// ```rust,ignore
13481/// let _result = pharos_native::runtime::json_commands::render_generated_surface_table_header_cell(std::path::Path::new("apps/dev_docs"), todo!());
13482/// ```
13483///
13484/// # Related
13485///
13486/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13487pub fn render_generated_surface_table_header_cell(app_root: &Path, label: &str) -> Option<String> {
13488    generated::render_generated_admin_fragment_from_value_runtime(
13489        app_root,
13490        "templates/generated_admin/fragments/table_header_cell.html",
13491        &Map::from_iter([("column_label".to_owned(), Value::String(label.to_owned()))]),
13492    )
13493}
13494
13495/// Renders a generated-surface table row cell.
13496///
13497/// # Parameters
13498///
13499/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_row_cell`].
13500/// - `value`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_row_cell`].
13501///
13502/// # Returns
13503///
13504/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_table_row_cell`] can produce a value and [`None`] otherwise.
13505///
13506/// # Examples
13507///
13508/// ```rust,ignore
13509/// let _result = pharos_native::runtime::json_commands::render_generated_surface_table_row_cell(std::path::Path::new("apps/dev_docs"), "value");
13510/// ```
13511///
13512/// # Related
13513///
13514/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13515pub fn render_generated_surface_table_row_cell(app_root: &Path, value: &str) -> Option<String> {
13516    generated::render_generated_admin_fragment_from_value_runtime(
13517        app_root,
13518        "templates/generated_admin/fragments/table_row_cell.html",
13519        &Map::from_iter([("field_value".to_owned(), Value::String(value.to_owned()))]),
13520    )
13521}
13522
13523/// Renders the action cell of one generated-surface row.
13524///
13525/// # Parameters
13526///
13527/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_action_cell`].
13528/// - `edit_path`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_action_cell`].
13529/// - `delete_path`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_action_cell`].
13530///
13531/// # Returns
13532///
13533/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_table_action_cell`] can produce a value and [`None`] otherwise.
13534///
13535/// # Examples
13536///
13537/// ```rust,ignore
13538/// let _result = pharos_native::runtime::json_commands::render_generated_surface_table_action_cell(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
13539/// ```
13540///
13541/// # Related
13542///
13543/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13544pub fn render_generated_surface_table_action_cell(
13545    app_root: &Path,
13546    edit_path: Option<&str>,
13547    delete_path: Option<&str>,
13548) -> Option<String> {
13549    let mut output = String::new();
13550    if let Some(path) = edit_path.filter(|value| !value.is_empty()) {
13551        output.push_str(&render_generated_surface_action_link(
13552            app_root, path, "Edit",
13553        )?);
13554    }
13555    if let Some(path) = delete_path.filter(|value| !value.is_empty()) {
13556        output.push_str(&render_generated_surface_delete_form(
13557            app_root, path, "Delete",
13558        )?);
13559    }
13560    Some(output)
13561}
13562
13563/// Renders one generated-surface table row from cell values.
13564///
13565/// # Parameters
13566///
13567/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_row`].
13568/// - `cells_html`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_row`].
13569/// - `action_cell_html`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_table_row`].
13570///
13571/// # Returns
13572///
13573/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_table_row`] can produce a value and [`None`] otherwise.
13574///
13575/// # Examples
13576///
13577/// ```rust,ignore
13578/// let _result = pharos_native::runtime::json_commands::render_generated_surface_table_row(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
13579/// ```
13580///
13581/// # Related
13582///
13583/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13584pub fn render_generated_surface_table_row(
13585    app_root: &Path,
13586    cells_html: &str,
13587    action_cell_html: &str,
13588) -> Option<String> {
13589    generated::render_generated_admin_fragment_from_value_runtime(
13590        app_root,
13591        "templates/generated_admin/fragments/table_row.html",
13592        &Map::from_iter([
13593            (
13594                "cells_html".to_owned(),
13595                Value::String(cells_html.to_owned()),
13596            ),
13597            (
13598                "action_cell_html".to_owned(),
13599                Value::String(action_cell_html.to_owned()),
13600            ),
13601        ]),
13602    )
13603}
13604
13605/// Tests whether an array contains a positive integer.
13606///
13607/// # Parameters
13608///
13609/// - `values`: Input consumed by [`crate::runtime::json_commands::json_array_contains_long`].
13610/// - `wanted`: Input consumed by [`crate::runtime::json_commands::json_array_contains_long`].
13611///
13612/// # Returns
13613///
13614/// Returns `true` when the condition checked by [`crate::runtime::json_commands::json_array_contains_long`] holds and `false` otherwise.
13615///
13616/// # Performance
13617///
13618/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_array_contains_long`].
13619///
13620/// # Examples
13621///
13622/// ```rust,ignore
13623/// let _result = pharos_native::runtime::json_commands::json_array_contains_long(todo!(), todo!());
13624/// ```
13625///
13626/// # Related
13627///
13628/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13629pub fn json_array_contains_long(values: &Value, wanted: i64) -> bool {
13630    values
13631        .as_array()
13632        .is_some_and(|items| items.iter().any(|item| item.as_i64() == Some(wanted)))
13633}
13634
13635/// Returns the first positive integer in a payload.
13636///
13637/// # Parameters
13638///
13639/// - `value`: Input consumed by [`crate::runtime::json_commands::payload_first_long`].
13640///
13641/// # Returns
13642///
13643/// Returns [`Some`] when [`crate::runtime::json_commands::payload_first_long`] can produce a value and [`None`] otherwise.
13644///
13645/// # Performance
13646///
13647/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::payload_first_long`].
13648///
13649/// # Examples
13650///
13651/// ```rust,ignore
13652/// let _result = pharos_native::runtime::json_commands::payload_first_long("value");
13653/// ```
13654///
13655/// # Related
13656///
13657/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13658pub fn payload_first_long(value: &Value) -> Option<i64> {
13659    match value {
13660        Value::Number(value) => value.as_i64().filter(|value| *value > 0),
13661        Value::Array(items) => items.iter().find_map(payload_first_long),
13662        Value::Object(object) => object.values().find_map(payload_first_long),
13663        _ => None,
13664    }
13665}
13666
13667/// Tests one JSON value against a signed integer.
13668///
13669/// # Parameters
13670///
13671/// - `value`: Input consumed by [`crate::runtime::json_commands::value_long_equals`].
13672/// - `wanted`: Input consumed by [`crate::runtime::json_commands::value_long_equals`].
13673///
13674/// # Returns
13675///
13676/// Returns `true` when the condition checked by [`crate::runtime::json_commands::value_long_equals`] holds and `false` otherwise.
13677///
13678/// # Examples
13679///
13680/// ```rust,ignore
13681/// let _result = pharos_native::runtime::json_commands::value_long_equals("value", todo!());
13682/// ```
13683///
13684/// # Related
13685///
13686/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13687pub fn value_long_equals(value: &Value, wanted: i64) -> bool {
13688    value.as_i64() == Some(wanted)
13689}
13690
13691/// Returns the bounded weekday rank used by calendar sorting.
13692///
13693/// # Parameters
13694///
13695/// - `value`: Input consumed by [`crate::runtime::json_commands::weekday_rank`].
13696///
13697/// # Returns
13698///
13699/// Returns the computed value produced by [`crate::runtime::json_commands::weekday_rank`].
13700///
13701/// # Examples
13702///
13703/// ```rust,ignore
13704/// let _result = pharos_native::runtime::json_commands::weekday_rank("value");
13705/// ```
13706///
13707/// # Related
13708///
13709/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13710pub fn weekday_rank(value: &str) -> u8 {
13711    match value.to_ascii_lowercase().as_str() {
13712        "mon" | "monday" => 1,
13713        "tue" | "tuesday" => 2,
13714        "wed" | "wednesday" => 3,
13715        "thu" | "thursday" => 4,
13716        "fri" | "friday" => 5,
13717        "sat" | "saturday" => 6,
13718        "sun" | "sunday" => 7,
13719        _ => 0,
13720    }
13721}
13722
13723/// Performs a case-insensitive equality check.
13724///
13725/// # Parameters
13726///
13727/// - `left`: Input consumed by [`crate::runtime::json_commands::streq_casefold`].
13728/// - `right`: Input consumed by [`crate::runtime::json_commands::streq_casefold`].
13729///
13730/// # Returns
13731///
13732/// Returns `true` when the condition checked by [`crate::runtime::json_commands::streq_casefold`] holds and `false` otherwise.
13733///
13734/// # Examples
13735///
13736/// ```rust,ignore
13737/// let _result = pharos_native::runtime::json_commands::streq_casefold(todo!(), todo!());
13738/// ```
13739///
13740/// # Related
13741///
13742/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13743pub fn streq_casefold(left: &str, right: &str) -> bool {
13744    left.eq_ignore_ascii_case(right)
13745}
13746
13747/// Returns the JSON array for one state section.
13748///
13749/// # Parameters
13750///
13751/// - `root`: Input consumed by [`crate::runtime::json_commands::state_array`].
13752/// - `section`: Input consumed by [`crate::runtime::json_commands::state_array`].
13753///
13754/// # Returns
13755///
13756/// Returns [`Some`] when [`crate::runtime::json_commands::state_array`] can produce a value and [`None`] otherwise.
13757///
13758/// # Examples
13759///
13760/// ```rust,ignore
13761/// let _result = pharos_native::runtime::json_commands::state_array(std::path::Path::new("."), "items");
13762/// ```
13763///
13764/// # Related
13765///
13766/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13767pub fn state_array(root: &Value, section: &str) -> Option<Vec<Value>> {
13768    Some(bounded_state_array(root, section).to_vec())
13769}
13770
13771/// Matches a generated-surface context against a request context.
13772///
13773/// # Parameters
13774///
13775/// - `surface`: Input consumed by [`crate::runtime::json_commands::surface_context_match`].
13776/// - `context`: Input consumed by [`crate::runtime::json_commands::surface_context_match`].
13777///
13778/// # Returns
13779///
13780/// Returns `true` when the condition checked by [`crate::runtime::json_commands::surface_context_match`] holds and `false` otherwise.
13781///
13782/// # Examples
13783///
13784/// ```rust,ignore
13785/// let _result = pharos_native::runtime::json_commands::surface_context_match(todo!(), todo!());
13786/// ```
13787///
13788/// # Related
13789///
13790/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13791pub fn surface_context_match(surface: &Value, context: &Value) -> bool {
13792    surface
13793        .get("context_binding")
13794        .and_then(Value::as_object)
13795        .is_none_or(|binding| {
13796            binding
13797                .get("param")
13798                .and_then(Value::as_str)
13799                .is_none_or(|param| surface.get(param) == context.get(param))
13800        })
13801}
13802
13803/// Renders a generated-surface submit button through the app-owned fragment.
13804///
13805/// # Parameters
13806///
13807/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_submit_button`].
13808/// - `label`: Input consumed by [`crate::runtime::json_commands::render_generated_surface_submit_button`].
13809///
13810/// # Returns
13811///
13812/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_surface_submit_button`] can produce a value and [`None`] otherwise.
13813///
13814/// # Examples
13815///
13816/// ```rust,ignore
13817/// let _result = pharos_native::runtime::json_commands::render_generated_surface_submit_button(std::path::Path::new("apps/dev_docs"), todo!());
13818/// ```
13819///
13820/// # Related
13821///
13822/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13823pub fn render_generated_surface_submit_button(app_root: &Path, label: &str) -> Option<String> {
13824    generated::render_generated_admin_fragment_from_value_runtime(
13825        app_root,
13826        "templates/shared/fragments/submit_button.html",
13827        &Map::from_iter([("button_label".to_owned(), Value::String(label.to_owned()))]),
13828    )
13829}
13830
13831/// Tests whether a bounded integer array contains one value.
13832///
13833/// # Parameters
13834///
13835/// - `values`: Input consumed by [`crate::runtime::json_commands::long_in_array`].
13836/// - `wanted`: Input consumed by [`crate::runtime::json_commands::long_in_array`].
13837///
13838/// # Returns
13839///
13840/// Returns `true` when the condition checked by [`crate::runtime::json_commands::long_in_array`] holds and `false` otherwise.
13841///
13842/// # Examples
13843///
13844/// ```rust,ignore
13845/// let _result = pharos_native::runtime::json_commands::long_in_array(todo!(), todo!());
13846/// ```
13847///
13848/// # Related
13849///
13850/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13851pub fn long_in_array(values: &Value, wanted: i64) -> bool {
13852    json_array_contains_long(values, wanted)
13853}
13854
13855/// Decodes one URL query component with plus and percent handling.
13856///
13857/// # Parameters
13858///
13859/// - `value`: Input consumed by [`crate::runtime::json_commands::url_decode`].
13860///
13861/// # Returns
13862///
13863/// Returns [`Some`] when [`crate::runtime::json_commands::url_decode`] can produce a value and [`None`] otherwise.
13864///
13865/// # Examples
13866///
13867/// ```rust,ignore
13868/// let _result = pharos_native::runtime::json_commands::url_decode("value");
13869/// ```
13870///
13871/// # Related
13872///
13873/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13874pub fn url_decode(value: &str) -> Option<String> {
13875    url_decode_component(value)
13876}
13877
13878/// Matches one generated API/admin operation in a contract file.
13879///
13880/// # Parameters
13881///
13882/// - `file_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_api_match`].
13883/// - `method`: Input consumed by [`crate::runtime::json_commands::generated_surface_api_match`].
13884/// - `request_path`: Input consumed by [`crate::runtime::json_commands::generated_surface_api_match`].
13885///
13886/// # Returns
13887///
13888/// Returns [`Some`] when [`crate::runtime::json_commands::generated_surface_api_match`] can produce a value and [`None`] otherwise.
13889///
13890/// # Examples
13891///
13892/// ```rust,ignore
13893/// let _result = pharos_native::runtime::json_commands::generated_surface_api_match(todo!(), todo!(), "/");
13894/// ```
13895///
13896/// # Related
13897///
13898/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13899pub fn generated_surface_api_match(
13900    file_path: &Path,
13901    method: &str,
13902    request_path: &str,
13903) -> Option<String> {
13904    file_generated_surface_match(file_path, method, request_path)
13905}
13906
13907/// Releases an owned generated-surface match result.
13908///
13909/// # Parameters
13910///
13911/// - `value`: Input consumed by [`crate::runtime::json_commands::generated_surface_api_match_free`].
13912///
13913/// # Returns
13914///
13915/// Returns after [`crate::runtime::json_commands::generated_surface_api_match_free`] applies its in-place effect.
13916///
13917/// # Examples
13918///
13919/// ```rust,ignore
13920/// let _result = pharos_native::runtime::json_commands::generated_surface_api_match_free("value");
13921/// ```
13922///
13923/// # Related
13924///
13925/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13926pub fn generated_surface_api_match_free(value: &mut Option<String>) {
13927    value.take();
13928}
13929
13930/// Matches a dynamic dispatch request against an app-owned route contract.
13931///
13932/// # Parameters
13933///
13934/// - `file_path`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_match`].
13935/// - `method`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_match`].
13936/// - `request_path`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_match`].
13937///
13938/// # Returns
13939///
13940/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_dispatch_match`] can produce a value and [`None`] otherwise.
13941///
13942/// # Examples
13943///
13944/// ```rust,ignore
13945/// let _result = pharos_native::runtime::json_commands::dynamic_dispatch_match(todo!(), todo!(), "/");
13946/// ```
13947///
13948/// # Related
13949///
13950/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13951pub fn dynamic_dispatch_match(
13952    file_path: &Path,
13953    method: &str,
13954    request_path: &str,
13955) -> Option<String> {
13956    generated_surface_api_match(file_path, method, request_path)
13957}
13958
13959/// Resolves a route fixture path below an app root without traversal.
13960///
13961/// # Parameters
13962///
13963/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_resolve_route_fixture`].
13964/// - `relative_path`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_resolve_route_fixture`].
13965///
13966/// # Returns
13967///
13968/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_dispatch_resolve_route_fixture`] can produce a value and [`None`] otherwise.
13969///
13970/// # Performance
13971///
13972/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_dispatch_resolve_route_fixture`].
13973///
13974/// # Examples
13975///
13976/// ```rust,ignore
13977/// let _result = pharos_native::runtime::json_commands::dynamic_dispatch_resolve_route_fixture(std::path::Path::new("apps/dev_docs"), "page");
13978/// ```
13979///
13980/// # Related
13981///
13982/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
13983pub fn dynamic_dispatch_resolve_route_fixture(
13984    app_root: &Path,
13985    relative_path: &str,
13986) -> Option<String> {
13987    if app_root.as_os_str().is_empty()
13988        || relative_path.is_empty()
13989        || Path::new(relative_path).is_absolute()
13990        || relative_path.split('/').any(|segment| segment == "..")
13991    {
13992        return None;
13993    }
13994    let path = app_root.join(relative_path);
13995    path.is_file().then(|| path.to_string_lossy().into_owned())
13996}
13997
13998/// Reads a bounded response file below an app artifact root.
13999///
14000/// # Parameters
14001///
14002/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_response_file`].
14003/// - `relative_path`: Input consumed by [`crate::runtime::json_commands::dynamic_dispatch_response_file`].
14004///
14005/// # Returns
14006///
14007/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_dispatch_response_file`] can produce a value and [`None`] otherwise.
14008///
14009/// # Performance
14010///
14011/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_dispatch_response_file`].
14012///
14013/// # Examples
14014///
14015/// ```rust,ignore
14016/// let _result = pharos_native::runtime::json_commands::dynamic_dispatch_response_file(std::path::Path::new("apps/dev_docs"), "page");
14017/// ```
14018///
14019/// # Related
14020///
14021/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14022pub fn dynamic_dispatch_response_file(app_root: &Path, relative_path: &str) -> Option<String> {
14023    let path = dynamic_dispatch_resolve_route_fixture(app_root, relative_path)?;
14024    let text = fs::read_to_string(path).ok()?;
14025    (text.len() <= MAX_TEXT_BYTES).then_some(text)
14026}
14027
14028/// Recognizes static media and static asset request paths.
14029///
14030/// # Parameters
14031///
14032/// - `path`: Input consumed by [`crate::runtime::json_commands::dynamic_media_is_static_path`].
14033///
14034/// # Returns
14035///
14036/// Returns `true` when the condition checked by [`crate::runtime::json_commands::dynamic_media_is_static_path`] holds and `false` otherwise.
14037///
14038/// # Examples
14039///
14040/// ```rust,ignore
14041/// let _result = pharos_native::runtime::json_commands::dynamic_media_is_static_path(std::path::Path::new("fixture.json"));
14042/// ```
14043///
14044/// # Related
14045///
14046/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14047pub fn dynamic_media_is_static_path(path: &str) -> bool {
14048    path.starts_with("/static/") || path.starts_with("/media/")
14049}
14050
14051/// Extracts the query component without decoding its individual values.
14052///
14053/// # Parameters
14054///
14055/// - `target`: Input consumed by [`crate::runtime::json_commands::extract_query`].
14056///
14057/// # Returns
14058///
14059/// Returns the computed value produced by [`crate::runtime::json_commands::extract_query`].
14060///
14061/// # Performance
14062///
14063/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::extract_query`].
14064///
14065/// # Examples
14066///
14067/// ```rust,ignore
14068/// let _result = pharos_native::runtime::json_commands::extract_query("/");
14069/// ```
14070///
14071/// # Related
14072///
14073/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14074pub fn extract_query(target: &str) -> String {
14075    target
14076        .split_once('?')
14077        .map(|(_, query)| query.split('#').next().unwrap_or_default().to_owned())
14078        .unwrap_or_default()
14079}
14080
14081/// Handles a framework webhook request using the shared endpoint contract.
14082///
14083/// # Parameters
14084///
14085/// - `root`: Input consumed by [`crate::runtime::json_commands::handle_framework_webhook_request`].
14086/// - `endpoint_id`: Input consumed by [`crate::runtime::json_commands::handle_framework_webhook_request`].
14087///
14088/// # Returns
14089///
14090/// Returns [`Some`] when [`crate::runtime::json_commands::handle_framework_webhook_request`] can produce a value and [`None`] otherwise.
14091///
14092/// # Performance
14093///
14094/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_framework_webhook_request`].
14095///
14096/// # Examples
14097///
14098/// ```rust,ignore
14099/// let _result = pharos_native::runtime::json_commands::handle_framework_webhook_request(std::path::Path::new("."), "webhook");
14100/// ```
14101///
14102/// # Related
14103///
14104/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14105pub fn handle_framework_webhook_request(root: &Value, endpoint_id: &str) -> Option<String> {
14106    if endpoint_id.is_empty() {
14107        return None;
14108    }
14109    bounded_state_array(root, "webhook_events")
14110        .iter()
14111        .find(|row| row.get("endpoint_id").and_then(Value::as_str) == Some(endpoint_id))
14112        .and_then(compact)
14113}
14114
14115/// Handles one generated-surface API request from a route-match document.
14116///
14117/// # Parameters
14118///
14119/// - `match_json`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_api_request`].
14120/// - `state_root`: Input consumed by [`crate::runtime::json_commands::handle_generated_surface_api_request`].
14121///
14122/// # Returns
14123///
14124/// Returns [`Some`] when [`crate::runtime::json_commands::handle_generated_surface_api_request`] can produce a value and [`None`] otherwise.
14125///
14126/// # Performance
14127///
14128/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_generated_surface_api_request`].
14129///
14130/// # Examples
14131///
14132/// ```rust,ignore
14133/// let _result = pharos_native::runtime::json_commands::handle_generated_surface_api_request(todo!(), todo!());
14134/// ```
14135///
14136/// # Related
14137///
14138/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14139pub fn handle_generated_surface_api_request(
14140    match_json: &str,
14141    state_root: &Value,
14142) -> Option<String> {
14143    let matched = serde_json::from_str::<Value>(match_json).ok()?;
14144    let operation = matched.get("operation").and_then(Value::as_str)?;
14145    compact(&serde_json::json!({"operation": operation, "state": state_root}))
14146}
14147
14148/// Handles one page route by returning its declared template path.
14149///
14150/// # Parameters
14151///
14152/// - `app_root`: Input consumed by [`crate::runtime::json_commands::handle_page_route`].
14153/// - `page_id`: Input consumed by [`crate::runtime::json_commands::handle_page_route`].
14154///
14155/// # Returns
14156///
14157/// Returns [`Some`] when [`crate::runtime::json_commands::handle_page_route`] can produce a value and [`None`] otherwise.
14158///
14159/// # Examples
14160///
14161/// ```rust,ignore
14162/// let _result = pharos_native::runtime::json_commands::handle_page_route(std::path::Path::new("apps/dev_docs"), "home");
14163/// ```
14164///
14165/// # Related
14166///
14167/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14168pub fn handle_page_route(app_root: &Path, page_id: &str) -> Option<String> {
14169    declared_page_relative_path(app_root, page_id)
14170}
14171
14172/// Handles one action route by returning its declared operation path.
14173///
14174/// # Parameters
14175///
14176/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::handle_action_route`].
14177/// - `operation`: Input consumed by [`crate::runtime::json_commands::handle_action_route`].
14178///
14179/// # Returns
14180///
14181/// Returns [`Some`] when [`crate::runtime::json_commands::handle_action_route`] can produce a value and [`None`] otherwise.
14182///
14183/// # Performance
14184///
14185/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::handle_action_route`].
14186///
14187/// # Examples
14188///
14189/// ```rust,ignore
14190/// let _result = pharos_native::runtime::json_commands::handle_action_route("{}", todo!());
14191/// ```
14192///
14193/// # Related
14194///
14195/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14196pub fn handle_action_route(surface_json: &str, operation: &str) -> Option<String> {
14197    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
14198    surface
14199        .get("operations")?
14200        .get(operation)?
14201        .get("path")
14202        .and_then(Value::as_str)
14203        .map(ToOwned::to_owned)
14204}
14205
14206/// Removes query and fragment components from a route request path.
14207///
14208/// # Parameters
14209///
14210/// - `target`: Input consumed by [`crate::runtime::json_commands::route_request_path`].
14211///
14212/// # Returns
14213///
14214/// Returns [`Some`] when [`crate::runtime::json_commands::route_request_path`] can produce a value and [`None`] otherwise.
14215///
14216/// # Examples
14217///
14218/// ```rust,ignore
14219/// let _result = pharos_native::runtime::json_commands::route_request_path("/");
14220/// ```
14221///
14222/// # Related
14223///
14224/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14225pub fn route_request_path(target: &str) -> Option<String> {
14226    super::http::request_path_without_query(target)
14227}
14228
14229/// Performs safe contract relative path.
14230fn safe_contract_relative_path(root: &Path, relative: &str) -> Option<PathBuf> {
14231    let path = Path::new(relative);
14232    if relative.is_empty() || path.is_absolute() {
14233        return None;
14234    }
14235    if path.components().any(|component| {
14236        matches!(
14237            component,
14238            Component::ParentDir | Component::RootDir | Component::Prefix(_)
14239        )
14240    }) {
14241        return None;
14242    }
14243    Some(root.join(path))
14244}
14245
14246/// Computes a lowercase SHA-256 digest without invoking an external process.
14247///
14248/// # Parameters
14249///
14250/// - `value`: Input consumed by [`crate::runtime::json_commands::migration_sha256_text`].
14251///
14252/// # Returns
14253///
14254/// Returns the computed value produced by [`crate::runtime::json_commands::migration_sha256_text`].
14255///
14256/// # Performance
14257///
14258/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::migration_sha256_text`].
14259///
14260/// # Examples
14261///
14262/// ```rust,ignore
14263/// let _result = pharos_native::runtime::json_commands::migration_sha256_text("value");
14264/// ```
14265///
14266/// # Related
14267///
14268/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14269pub fn migration_sha256_text(value: &str) -> String {
14270    let digest = Sha256::digest(value.as_bytes());
14271    digest.iter().map(|byte| format!("{byte:02x}")).collect()
14272}
14273
14274/// Returns a JSON literal string, preserving the caller-supplied literal text.
14275///
14276/// # Parameters
14277///
14278/// - `value`: Input consumed by [`crate::runtime::json_commands::json_literal`].
14279///
14280/// # Returns
14281///
14282/// Returns the computed value produced by [`crate::runtime::json_commands::json_literal`].
14283///
14284/// # Examples
14285///
14286/// ```rust,ignore
14287/// let _result = pharos_native::runtime::json_commands::json_literal("value");
14288/// ```
14289///
14290/// # Related
14291///
14292/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14293pub fn json_literal(value: &str) -> String {
14294    value.to_owned()
14295}
14296
14297/// Serializes an optional string as JSON, using the JSON null literal when absent.
14298///
14299/// # Parameters
14300///
14301/// - `value`: Input consumed by [`crate::runtime::json_commands::json_nullable_string`].
14302///
14303/// # Returns
14304///
14305/// Returns the computed value produced by [`crate::runtime::json_commands::json_nullable_string`].
14306///
14307/// # Examples
14308///
14309/// ```rust,ignore
14310/// let _result = pharos_native::runtime::json_commands::json_nullable_string("value");
14311/// ```
14312///
14313/// # Related
14314///
14315/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14316pub fn json_nullable_string(value: Option<&str>) -> String {
14317    value
14318        .filter(|text| !text.is_empty())
14319        .map(|text| serde_json::to_string(text).unwrap_or_else(|_| "null".to_owned()))
14320        .unwrap_or_else(|| "null".to_owned())
14321}
14322
14323/// Serializes a JSON value or returns a validated fallback literal.
14324///
14325/// # Parameters
14326///
14327/// - `value`: Input consumed by [`crate::runtime::json_commands::json_value_or_literal`].
14328/// - `fallback`: Input consumed by [`crate::runtime::json_commands::json_value_or_literal`].
14329///
14330/// # Returns
14331///
14332/// Returns the computed value produced by [`crate::runtime::json_commands::json_value_or_literal`].
14333///
14334/// # Examples
14335///
14336/// ```rust,ignore
14337/// let _result = pharos_native::runtime::json_commands::json_value_or_literal("value", todo!());
14338/// ```
14339///
14340/// # Related
14341///
14342/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14343pub fn json_value_or_literal(value: Option<&Value>, fallback: &str) -> String {
14344    value
14345        .and_then(|item| serde_json::to_string(item).ok())
14346        .unwrap_or_else(|| fallback.to_owned())
14347}
14348
14349/// Serializes an object string field with a plain-string fallback.
14350///
14351/// # Parameters
14352///
14353/// - `value`: Input consumed by [`crate::runtime::json_commands::json_object_string_json`].
14354/// - `key`: Input consumed by [`crate::runtime::json_commands::json_object_string_json`].
14355/// - `fallback`: Input consumed by [`crate::runtime::json_commands::json_object_string_json`].
14356///
14357/// # Returns
14358///
14359/// Returns the computed value produced by [`crate::runtime::json_commands::json_object_string_json`].
14360///
14361/// # Examples
14362///
14363/// ```rust,ignore
14364/// let _result = pharos_native::runtime::json_commands::json_object_string_json("value", "key", todo!());
14365/// ```
14366///
14367/// # Related
14368///
14369/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14370pub fn json_object_string_json(value: &Value, key: &str, fallback: &str) -> String {
14371    let text = value.get(key).and_then(Value::as_str).unwrap_or(fallback);
14372    serde_json::to_string(text).unwrap_or_else(|_| "\"\"".to_owned())
14373}
14374
14375/// Serializes an integer as JSON number text.
14376///
14377/// # Parameters
14378///
14379/// - `value`: Input consumed by [`crate::runtime::json_commands::long_json`].
14380///
14381/// # Returns
14382///
14383/// Returns the computed value produced by [`crate::runtime::json_commands::long_json`].
14384///
14385/// # Examples
14386///
14387/// ```rust,ignore
14388/// let _result = pharos_native::runtime::json_commands::long_json("value");
14389/// ```
14390///
14391/// # Related
14392///
14393/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14394pub fn long_json(value: i64) -> String {
14395    value.to_string()
14396}
14397
14398/// Appends one serialized item to a JSON array under construction.
14399///
14400/// # Parameters
14401///
14402/// - `buffer`: Input consumed by [`crate::runtime::json_commands::append_json_item`].
14403/// - `json_item`: Input consumed by [`crate::runtime::json_commands::append_json_item`].
14404/// - `first`: Input consumed by [`crate::runtime::json_commands::append_json_item`].
14405///
14406/// # Returns
14407///
14408/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_json_item`] holds and `false` otherwise.
14409///
14410/// # Examples
14411///
14412/// ```rust,ignore
14413/// let _result = pharos_native::runtime::json_commands::append_json_item(&mut [], todo!(), todo!());
14414/// ```
14415///
14416/// # Related
14417///
14418/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14419pub fn append_json_item(buffer: &mut String, json_item: &str, first: &mut bool) -> bool {
14420    if json_item.is_empty() {
14421        return false;
14422    }
14423    if *first {
14424        buffer.push('[');
14425        *first = false;
14426    } else if buffer.is_empty() || buffer.ends_with(']') {
14427        return false;
14428    } else {
14429        buffer.push(',');
14430    }
14431    buffer.push_str(json_item);
14432    true
14433}
14434
14435/// Serializes and appends one string item to a JSON array under construction.
14436///
14437/// # Parameters
14438///
14439/// - `buffer`: Input consumed by [`crate::runtime::json_commands::append_json_string_item`].
14440/// - `value`: Input consumed by [`crate::runtime::json_commands::append_json_string_item`].
14441/// - `first`: Input consumed by [`crate::runtime::json_commands::append_json_string_item`].
14442///
14443/// # Returns
14444///
14445/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_json_string_item`] holds and `false` otherwise.
14446///
14447/// # Examples
14448///
14449/// ```rust,ignore
14450/// let _result = pharos_native::runtime::json_commands::append_json_string_item(&mut [], "value", todo!());
14451/// ```
14452///
14453/// # Related
14454///
14455/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14456pub fn append_json_string_item(buffer: &mut String, value: Option<&str>, first: &mut bool) -> bool {
14457    let item = serde_json::to_string(value.unwrap_or_default()).ok();
14458    item.as_deref()
14459        .is_some_and(|json| append_json_item(buffer, json, first))
14460}
14461
14462/// Completes a JSON array under construction.
14463///
14464/// # Parameters
14465///
14466/// - `buffer`: Input consumed by [`crate::runtime::json_commands::finish_json_array`].
14467/// - `first`: Input consumed by [`crate::runtime::json_commands::finish_json_array`].
14468///
14469/// # Returns
14470///
14471/// Returns [`Some`] when [`crate::runtime::json_commands::finish_json_array`] can produce a value and [`None`] otherwise.
14472///
14473/// # Examples
14474///
14475/// ```rust,ignore
14476/// let _result = pharos_native::runtime::json_commands::finish_json_array(&mut [], todo!());
14477/// ```
14478///
14479/// # Related
14480///
14481/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14482pub fn finish_json_array(buffer: &mut String, first: bool) -> Option<String> {
14483    if first {
14484        return Some("[]".to_owned());
14485    }
14486    if !buffer.starts_with('[') || buffer.ends_with(']') {
14487        return None;
14488    }
14489    buffer.push(']');
14490    Some(buffer.clone())
14491}
14492
14493/// Checks a seed row count against exact and minimum expectations.
14494///
14495/// # Parameters
14496///
14497/// - `row_count`: Observed seeded row count.
14498/// - `minimum_rows`: Optional minimum row threshold to enforce.
14499/// - `exact_rows`: Optional exact row count to enforce.
14500///
14501/// # Returns
14502///
14503/// Returns the successful value produced by [`crate::runtime::json_commands::seed_expectation_satisfied`] or an error when the operation fails.
14504///
14505/// # Errors
14506///
14507/// Returns an error value when [`crate::runtime::json_commands::seed_expectation_satisfied`] cannot complete successfully.
14508///
14509/// # Examples
14510///
14511/// ```rust,ignore
14512/// let _result = pharos_native::runtime::json_commands::seed_expectation_satisfied(todo!(), todo!(), todo!(), todo!());
14513/// ```
14514///
14515/// # Related
14516///
14517/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14518pub fn seed_expectation_satisfied(
14519    row_count: i64,
14520    minimum_rows: Option<i64>,
14521    exact_rows: Option<i64>,
14522) -> Result<(), &'static str> {
14523    if exact_rows.is_some_and(|expected| row_count != expected) {
14524        return Err("exact_rows_mismatch");
14525    }
14526    if minimum_rows.is_some_and(|minimum| row_count < minimum) {
14527        return Err("minimum_rows_not_met");
14528    }
14529    Ok(())
14530}
14531
14532/// Checks whether an applied migration checksum matches any accepted checksum.
14533///
14534/// # Parameters
14535///
14536/// - `applied`: Input consumed by [`crate::runtime::json_commands::migration_checksum_matches`].
14537/// - `applied_checksum`: Input consumed by [`crate::runtime::json_commands::migration_checksum_matches`].
14538/// - `expected_checksum`: Input consumed by [`crate::runtime::json_commands::migration_checksum_matches`].
14539///
14540/// # Returns
14541///
14542/// Returns `true` when the condition checked by [`crate::runtime::json_commands::migration_checksum_matches`] holds and `false` otherwise.
14543///
14544/// # Examples
14545///
14546/// ```rust,ignore
14547/// let _result = pharos_native::runtime::json_commands::migration_checksum_matches(todo!(), todo!(), todo!());
14548/// ```
14549///
14550/// # Related
14551///
14552/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14553pub fn migration_checksum_matches(
14554    applied: bool,
14555    applied_checksum: Option<&str>,
14556    expected_checksum: Option<&str>,
14557) -> bool {
14558    let Some(applied_checksum) = applied_checksum.filter(|value| !value.is_empty()) else {
14559        return false;
14560    };
14561    if !applied {
14562        return false;
14563    }
14564    expected_checksum == Some(applied_checksum)
14565}
14566
14567/// Returns a migration contract path declared by an app manifest.
14568///
14569/// # Parameters
14570///
14571/// - `app_root`: Input consumed by [`crate::runtime::json_commands::migration_fixture_path_dup_runtime_local`].
14572///
14573/// # Returns
14574///
14575/// Returns [`Some`] when [`crate::runtime::json_commands::migration_fixture_path_dup_runtime_local`] can produce a value and [`None`] otherwise.
14576///
14577/// # Examples
14578///
14579/// ```rust,ignore
14580/// let _result = pharos_native::runtime::json_commands::migration_fixture_path_dup_runtime_local(std::path::Path::new("apps/dev_docs"));
14581/// ```
14582///
14583/// # Related
14584///
14585/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14586pub fn migration_fixture_path_dup_runtime_local(app_root: &Path) -> Option<PathBuf> {
14587    let relative = manifest_database_contract_path(app_root)?;
14588    safe_contract_relative_path(app_root, &relative)
14589}
14590
14591/// Returns a backend record from an array of JSON objects by exact string field.
14592///
14593/// # Parameters
14594///
14595/// - `array`: Input consumed by [`crate::runtime::json_commands::json_find_object_by_string_field`].
14596/// - `field_name`: Input consumed by [`crate::runtime::json_commands::json_find_object_by_string_field`].
14597/// - `expected_value`: Input consumed by [`crate::runtime::json_commands::json_find_object_by_string_field`].
14598///
14599/// # Returns
14600///
14601/// Returns [`Some`] when [`crate::runtime::json_commands::json_find_object_by_string_field`] can produce a value and [`None`] otherwise.
14602///
14603/// # Performance
14604///
14605/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_find_object_by_string_field`].
14606///
14607/// # Examples
14608///
14609/// ```rust,ignore
14610/// let _result = pharos_native::runtime::json_commands::json_find_object_by_string_field(todo!(), todo!(), todo!());
14611/// ```
14612///
14613/// # Related
14614///
14615/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14616pub fn json_find_object_by_string_field<'a>(
14617    array: &'a Value,
14618    field_name: &str,
14619    expected_value: &str,
14620) -> Option<&'a Value> {
14621    array
14622        .as_array()?
14623        .iter()
14624        .find(|item| item.get(field_name).and_then(Value::as_str) == Some(expected_value))
14625}
14626
14627/// Finds a migration record by its stable migration id.
14628///
14629/// # Parameters
14630///
14631/// - `root`: Input consumed by [`crate::runtime::json_commands::json_find_migration_by_id`].
14632/// - `migration_id`: Input consumed by [`crate::runtime::json_commands::json_find_migration_by_id`].
14633///
14634/// # Returns
14635///
14636/// Returns [`Some`] when [`crate::runtime::json_commands::json_find_migration_by_id`] can produce a value and [`None`] otherwise.
14637///
14638/// # Examples
14639///
14640/// ```rust,ignore
14641/// let _result = pharos_native::runtime::json_commands::json_find_migration_by_id(std::path::Path::new("."), "001_init");
14642/// ```
14643///
14644/// # Related
14645///
14646/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14647pub fn json_find_migration_by_id<'a>(root: &'a Value, migration_id: &str) -> Option<&'a Value> {
14648    json_find_object_by_string_field(root.get("migrations")?, "migration_id", migration_id)
14649}
14650
14651/// Computes a bounded content signature for relational state synchronization.
14652///
14653/// # Parameters
14654///
14655/// - `path`: Input consumed by [`crate::runtime::json_commands::dynamic_relational_file_signature`].
14656///
14657/// # Returns
14658///
14659/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_relational_file_signature`] can produce a value and [`None`] otherwise.
14660///
14661/// # Performance
14662///
14663/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_relational_file_signature`].
14664///
14665/// # Examples
14666///
14667/// ```rust,ignore
14668/// let _result = pharos_native::runtime::json_commands::dynamic_relational_file_signature(std::path::Path::new("fixture.json"));
14669/// ```
14670///
14671/// # Related
14672///
14673/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14674pub fn dynamic_relational_file_signature(path: &Path) -> Option<String> {
14675    if path.as_os_str().is_empty() {
14676        return None;
14677    }
14678    if !path.exists() {
14679        return Some("missing".to_owned());
14680    }
14681    let bytes = fs::read(path).ok()?;
14682    let mut hash = 1469598103934665603u64;
14683    for byte in &bytes {
14684        hash ^= u64::from(*byte);
14685        hash = hash.wrapping_mul(1099511628211);
14686    }
14687    Some(format!("{hash:016x}:{}", bytes.len()))
14688}
14689
14690/// Emits a generated-surface schema response from contract JSON.
14691///
14692/// # Parameters
14693///
14694/// - `surface_json`: Input consumed by [`crate::runtime::json_commands::write_generated_surface_schema_response`].
14695///
14696/// # Returns
14697///
14698/// Returns [`Some`] when [`crate::runtime::json_commands::write_generated_surface_schema_response`] can produce a value and [`None`] otherwise.
14699///
14700/// # Performance
14701///
14702/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::write_generated_surface_schema_response`].
14703///
14704/// # Examples
14705///
14706/// ```rust,ignore
14707/// let _result = pharos_native::runtime::json_commands::write_generated_surface_schema_response("{}");
14708/// ```
14709///
14710/// # Related
14711///
14712/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14713pub fn write_generated_surface_schema_response(surface_json: &str) -> Option<String> {
14714    let surface = serde_json::from_str::<Value>(surface_json).ok()?;
14715    compact(surface.get("schema").unwrap_or(&surface))
14716}
14717
14718/// Renders a bounded path template with explicit placeholder replacement.
14719///
14720/// # Parameters
14721///
14722/// - `template`: Input consumed by [`crate::runtime::json_commands::render_path_template_text`].
14723/// - `values`: Input consumed by [`crate::runtime::json_commands::render_path_template_text`].
14724///
14725/// # Returns
14726///
14727/// Returns [`Some`] when [`crate::runtime::json_commands::render_path_template_text`] can produce a value and [`None`] otherwise.
14728///
14729/// # Performance
14730///
14731/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::render_path_template_text`].
14732///
14733/// # Examples
14734///
14735/// ```rust,ignore
14736/// let _result = pharos_native::runtime::json_commands::render_path_template_text(todo!(), todo!());
14737/// ```
14738///
14739/// # Related
14740///
14741/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14742pub fn render_path_template_text(template: &str, values: &Value) -> Option<String> {
14743    if template.len() > 64 * 1024 {
14744        return None;
14745    }
14746    let mut output = template.to_owned();
14747    if let Some(map) = values.as_object() {
14748        for (key, value) in map {
14749            let text = value
14750                .as_str()
14751                .or_else(|| {
14752                    value
14753                        .as_i64()
14754                        .map(|number| Box::leak(number.to_string().into_boxed_str()) as &str)
14755                })
14756                .unwrap_or_default();
14757            output = output.replace(&format!("{{{key}}}"), text);
14758        }
14759    }
14760    Some(output)
14761}
14762
14763/// Serializes one JSON value using the compact runtime policy.
14764///
14765/// # Parameters
14766///
14767/// - `value`: Input consumed by [`crate::runtime::json_commands::json_value_tostring`].
14768///
14769/// # Returns
14770///
14771/// Returns [`Some`] when [`crate::runtime::json_commands::json_value_tostring`] can produce a value and [`None`] otherwise.
14772///
14773/// # Examples
14774///
14775/// ```rust,ignore
14776/// let _result = pharos_native::runtime::json_commands::json_value_tostring("value");
14777/// ```
14778///
14779/// # Related
14780///
14781/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14782pub fn json_value_tostring(value: &Value) -> Option<String> {
14783    serde_json::to_string(value).ok()
14784}
14785
14786/// Resolves the declared deletion strategy with a safe default.
14787///
14788/// # Parameters
14789///
14790/// - `surface`: Input consumed by [`crate::runtime::json_commands::generated_surface_delete_strategy`].
14791///
14792/// # Returns
14793///
14794/// Returns the computed value produced by [`crate::runtime::json_commands::generated_surface_delete_strategy`].
14795///
14796/// # Examples
14797///
14798/// ```rust,ignore
14799/// let _result = pharos_native::runtime::json_commands::generated_surface_delete_strategy(todo!());
14800/// ```
14801///
14802/// # Related
14803///
14804/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14805pub fn generated_surface_delete_strategy(surface: &Value) -> String {
14806    surface
14807        .get("delete_strategy")
14808        .and_then(Value::as_str)
14809        .filter(|value| matches!(*value, "soft" | "hard" | "none"))
14810        .unwrap_or("soft")
14811        .to_owned()
14812}
14813
14814/// Renders a public-state button fragment with HTML-escaped business context.
14815///
14816/// # Parameters
14817///
14818/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_public_state_button_html`].
14819/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_public_state_button_html`].
14820/// - `is_public`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_public_state_button_html`].
14821///
14822/// # Returns
14823///
14824/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_render_business_admin_public_state_button_html`] can produce a value and [`None`] otherwise.
14825///
14826/// # Examples
14827///
14828/// ```rust,ignore
14829/// let _result = pharos_native::runtime::json_commands::dynamic_render_business_admin_public_state_button_html(std::path::Path::new("apps/dev_docs"), "demo", todo!());
14830/// ```
14831///
14832/// # Related
14833///
14834/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14835pub fn dynamic_render_business_admin_public_state_button_html(
14836    app_root: &Path,
14837    business_slug: &str,
14838    is_public: bool,
14839) -> Option<String> {
14840    if app_root.as_os_str().is_empty()
14841        || business_slug.is_empty()
14842        || business_slug.contains(['/', '\\'])
14843    {
14844        return None;
14845    }
14846    let button_label = if is_public { "Public" } else { "Private" };
14847    render_fragment_with_params(
14848        app_root,
14849        "templates/shared/fragments/public_state_toggle_button.html",
14850        serde_json::Map::from_iter([
14851            (
14852                "button_label".to_owned(),
14853                Value::String(button_label.to_owned()),
14854            ),
14855            ("is_public".to_owned(), Value::String(is_public.to_string())),
14856            (
14857                "state_class".to_owned(),
14858                Value::String(
14859                    if is_public {
14860                        "business-is-public"
14861                    } else {
14862                        "business-is-private"
14863                    }
14864                    .to_owned(),
14865                ),
14866            ),
14867        ]),
14868    )
14869}
14870
14871/// Renders availability rows from an app-owned state document.
14872///
14873/// # Parameters
14874///
14875/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_availability_rows_html`].
14876/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_availability_rows_html`].
14877/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_availability_rows_html`].
14878///
14879/// # Returns
14880///
14881/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_render_business_admin_availability_rows_html`] can produce a value and [`None`] otherwise.
14882///
14883/// # Performance
14884///
14885/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_render_business_admin_availability_rows_html`].
14886///
14887/// # Examples
14888///
14889/// ```rust,ignore
14890/// let _result = pharos_native::runtime::json_commands::dynamic_render_business_admin_availability_rows_html(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
14891/// ```
14892///
14893/// # Related
14894///
14895/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
14896pub fn dynamic_render_business_admin_availability_rows_html(
14897    root: &Value,
14898    business_slug: &str,
14899    app_root: &Path,
14900) -> Option<String> {
14901    if app_root.as_os_str().is_empty() || business_slug.is_empty() {
14902        return None;
14903    }
14904    let business_id = state_row_by_id(
14905        &serde_json::json!({
14906            "businesses": bounded_state_array(root, "businesses")
14907                .iter()
14908                .filter(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))
14909                .cloned()
14910                .collect::<Vec<_>>()
14911        }),
14912        "businesses",
14913        bounded_state_array(root, "businesses")
14914            .iter()
14915            .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))
14916            .and_then(|row| row.get("id").and_then(Value::as_i64))?,
14917    )?
14918    .get("id")
14919    .and_then(Value::as_i64)?;
14920    let mut availability_rows = bounded_state_array(root, "business_availability")
14921        .iter()
14922        .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
14923        .collect::<Vec<_>>();
14924    availability_rows.sort_by_key(|row| {
14925        (
14926            weekday_rank(
14927                &row.get("day_of_week")
14928                    .map(value_to_text)
14929                    .unwrap_or_default(),
14930            ),
14931            row.get("start_time").map(value_to_text).unwrap_or_default(),
14932            row.get("id").and_then(Value::as_i64).unwrap_or_default(),
14933        )
14934    });
14935    let mut output = String::new();
14936    for row in availability_rows {
14937        let availability_id = row.get("id").and_then(Value::as_i64)?;
14938        let day_of_week = row
14939            .get("day_of_week")
14940            .map(value_to_text)
14941            .unwrap_or_default();
14942        let start_time = row
14943            .get("start_time")
14944            .map(value_to_text)
14945            .filter(|value| !value.is_empty())
14946            .unwrap_or_else(|| "09:00".to_owned());
14947        let end_time = row
14948            .get("end_time")
14949            .map(value_to_text)
14950            .filter(|value| !value.is_empty())
14951            .unwrap_or_else(|| "17:00".to_owned());
14952        let hidden_day_input = render_fragment_with_params(
14953            app_root,
14954            "templates/shared/fragments/ui_hidden_input.html",
14955            serde_json::Map::from_iter([
14956                (
14957                    "id".to_owned(),
14958                    Value::String("availability_row_day_hidden_input".to_owned()),
14959                ),
14960                ("name".to_owned(), Value::String("day_of_week".to_owned())),
14961                ("value".to_owned(), Value::String(day_of_week.clone())),
14962                ("attributes_html".to_owned(), Value::String(String::new())),
14963            ]),
14964        )?;
14965        let start_input = render_fragment_with_params(
14966            app_root,
14967            "templates/shared/fragments/ui_input.html",
14968            serde_json::Map::from_iter([
14969                (
14970                    "id".to_owned(),
14971                    Value::String("availability_row_start_time_input".to_owned()),
14972                ),
14973                ("input_type".to_owned(), Value::String("time".to_owned())),
14974                ("name".to_owned(), Value::String("start_time".to_owned())),
14975                ("label".to_owned(), Value::String("Start time".to_owned())),
14976                (
14977                    "label_class".to_owned(),
14978                    Value::String("sr-only".to_owned()),
14979                ),
14980                (
14981                    "class_name".to_owned(),
14982                    Value::String("form-control availability-inline-input".to_owned()),
14983                ),
14984                ("value".to_owned(), Value::String(start_time.clone())),
14985                (
14986                    "attributes_html".to_owned(),
14987                    Value::String(" aria-label=\"Start time\"".to_owned()),
14988                ),
14989                ("help_html".to_owned(), Value::String(String::new())),
14990            ]),
14991        )?;
14992        let end_input = render_fragment_with_params(
14993            app_root,
14994            "templates/shared/fragments/ui_input.html",
14995            serde_json::Map::from_iter([
14996                (
14997                    "id".to_owned(),
14998                    Value::String("availability_row_end_time_input".to_owned()),
14999                ),
15000                ("input_type".to_owned(), Value::String("time".to_owned())),
15001                ("name".to_owned(), Value::String("end_time".to_owned())),
15002                ("label".to_owned(), Value::String("End time".to_owned())),
15003                (
15004                    "label_class".to_owned(),
15005                    Value::String("sr-only".to_owned()),
15006                ),
15007                (
15008                    "class_name".to_owned(),
15009                    Value::String("form-control availability-inline-input".to_owned()),
15010                ),
15011                ("value".to_owned(), Value::String(end_time.clone())),
15012                (
15013                    "attributes_html".to_owned(),
15014                    Value::String(" aria-label=\"End time\"".to_owned()),
15015                ),
15016                ("help_html".to_owned(), Value::String(String::new())),
15017            ]),
15018        )?;
15019        let save_button = render_fragment_with_params(
15020            app_root,
15021            "templates/shared/fragments/ui_button.html",
15022            serde_json::Map::from_iter([
15023                (
15024                    "id".to_owned(),
15025                    Value::String("availability_row_save_button".to_owned()),
15026                ),
15027                ("button_type".to_owned(), Value::String("submit".to_owned())),
15028                (
15029                    "class_name".to_owned(),
15030                    Value::String(
15031                        "btn btn-success btn-icon btn-icon-sm business-admin-save-button"
15032                            .to_owned(),
15033                    ),
15034                ),
15035                (
15036                    "attributes_html".to_owned(),
15037                    Value::String(
15038                        " title=\"Save Availability\" aria-label=\"Save Availability\"".to_owned(),
15039                    ),
15040                ),
15041                (
15042                    "content_html".to_owned(),
15043                    Value::String(
15044                        generated::render_generated_admin_fragment_from_value_runtime(
15045                            app_root,
15046                            "templates/shared/fragments/ui_content_save_availability.html",
15047                            &serde_json::Map::new(),
15048                        )?,
15049                    ),
15050                ),
15051            ]),
15052        )?;
15053        let delete_button = render_fragment_with_params(
15054            app_root,
15055            "templates/shared/fragments/ui_button.html",
15056            serde_json::Map::from_iter([
15057                (
15058                    "id".to_owned(),
15059                    Value::String("availability_row_delete_button".to_owned()),
15060                ),
15061                ("button_type".to_owned(), Value::String("button".to_owned())),
15062                (
15063                    "class_name".to_owned(),
15064                    Value::String("btn btn-danger btn-icon btn-icon-sm".to_owned()),
15065                ),
15066                (
15067                    "attributes_html".to_owned(),
15068                    Value::String(format!(
15069                        " title=\"Delete Availability\" aria-label=\"Delete Availability\" hx-post=\"/businesses/{business_slug}/availability/{availability_id}/delete/\" hx-include=\"closest form\" hx-target=\"#business-availability-rows\" hx-swap=\"innerHTML\""
15070                    )),
15071                ),
15072                (
15073                    "content_html".to_owned(),
15074                    Value::String(
15075                        generated::render_generated_admin_fragment_from_value_runtime(
15076                            app_root,
15077                            "templates/shared/fragments/ui_content_delete_availability.html",
15078                            &serde_json::Map::new(),
15079                        )?,
15080                    ),
15081                ),
15082            ]),
15083        )?;
15084        output.push_str(&render_fragment_with_params(
15085            app_root,
15086            "templates/businesses/fragments/business_admin_availability_row.html",
15087            serde_json::Map::from_iter([
15088                ("day_of_week".to_owned(), Value::String(day_of_week)),
15089                (
15090                    "start_display".to_owned(),
15091                    Value::String(start_time.clone()),
15092                ),
15093                ("end_display".to_owned(), Value::String(end_time.clone())),
15094                (
15095                    "save_path".to_owned(),
15096                    Value::String(format!(
15097                        "/businesses/{business_slug}/availability/{availability_id}/edit/"
15098                    )),
15099                ),
15100                (
15101                    "availability_row_day_hidden_input_ui_html".to_owned(),
15102                    Value::String(hidden_day_input),
15103                ),
15104                (
15105                    "availability_row_start_time_input_ui_html".to_owned(),
15106                    Value::String(start_input),
15107                ),
15108                (
15109                    "availability_row_end_time_input_ui_html".to_owned(),
15110                    Value::String(end_input),
15111                ),
15112                (
15113                    "availability_row_save_button_ui_html".to_owned(),
15114                    Value::String(save_button),
15115                ),
15116                (
15117                    "availability_row_delete_button_ui_html".to_owned(),
15118                    Value::String(delete_button),
15119                ),
15120            ]),
15121        )?);
15122    }
15123    Some(output)
15124}
15125
15126/// Performs page params value.
15127fn page_params_value(root: &Value, page_id: &str, extra: Map<String, Value>) -> Option<String> {
15128    if page_id.is_empty() {
15129        return None;
15130    }
15131    let mut params = Map::new();
15132    params.insert("page_id".to_owned(), Value::String(page_id.to_owned()));
15133    params.insert("state".to_owned(), Value::Object(extra));
15134    params.insert(
15135        "record_count".to_owned(),
15136        Value::from(root.as_object().map(|object| object.len()).unwrap_or(0)),
15137    );
15138    compact(&Value::Object(params))
15139}
15140
15141fn row_i64_value(row: &Value, field: &str) -> Option<i64> {
15142    row.get(field).and_then(Value::as_i64).or_else(|| {
15143        row.get(field)
15144            .and_then(Value::as_str)
15145            .and_then(|value| value.parse::<i64>().ok())
15146    })
15147}
15148
15149fn state_row_by_i64<'a>(
15150    root: &'a Value,
15151    section: &str,
15152    field: &str,
15153    expected: i64,
15154) -> Option<&'a Value> {
15155    bounded_state_array(root, section)
15156        .iter()
15157        .find(|row| row_i64_value(row, field) == Some(expected))
15158}
15159
15160fn row_date_time(row: &Value) -> (String, String) {
15161    let date = row
15162        .get("date")
15163        .map(value_to_text)
15164        .filter(|value| !value.is_empty())
15165        .or_else(|| {
15166            row.get("start_time")
15167                .map(value_to_text)
15168                .and_then(|value| value.get(0..10).map(ToOwned::to_owned))
15169        })
15170        .unwrap_or_default();
15171    let time = row
15172        .get("time")
15173        .map(value_to_text)
15174        .filter(|value| !value.is_empty())
15175        .or_else(|| {
15176            row.get("start_time")
15177                .map(value_to_text)
15178                .and_then(|value| value.get(11..16).map(ToOwned::to_owned))
15179        })
15180        .unwrap_or_default();
15181    (date, time)
15182}
15183
15184/// Builds the availability edit page parameters from persisted state.
15185///
15186/// # Parameters
15187///
15188/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`].
15189/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`].
15190/// - `availability_id`: Input consumed by [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`].
15191/// - `error_text`: Input consumed by [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`].
15192/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`].
15193///
15194/// # Returns
15195///
15196/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_availability_edit_page_params_json`] can produce a value and [`None`] otherwise.
15197///
15198/// # Examples
15199///
15200/// ```rust,ignore
15201/// let _result = pharos_native::runtime::json_commands::dynamic_business_availability_edit_page_params_json(todo!(), "demo", todo!(), todo!(), std::path::Path::new("apps/dev_docs"));
15202/// ```
15203///
15204/// # Related
15205///
15206/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15207pub fn dynamic_business_availability_edit_page_params_json(
15208    state_path: &Path,
15209    business_slug: &str,
15210    availability_id: i64,
15211    error_text: &str,
15212    app_root: &Path,
15213) -> Option<String> {
15214    let root = json_doc_load_file(state_path)?;
15215    let mut extra = Map::new();
15216    extra.insert("business_slug".into(), Value::String(business_slug.into()));
15217    extra.insert("availability_id".into(), Value::from(availability_id));
15218    extra.insert("error".into(), Value::String(error_text.into()));
15219    extra.insert(
15220        "app_root".into(),
15221        Value::String(app_root.to_string_lossy().into_owned()),
15222    );
15223    page_params_value(&root, "business-availability-edit", extra)
15224}
15225
15226/// Builds the business delete confirmation page parameters.
15227///
15228/// # Parameters
15229///
15230/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_delete_confirm_page_params_json`].
15231/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_delete_confirm_page_params_json`].
15232///
15233/// # Returns
15234///
15235/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_delete_confirm_page_params_json`] can produce a value and [`None`] otherwise.
15236///
15237/// # Examples
15238///
15239/// ```rust,ignore
15240/// let _result = pharos_native::runtime::json_commands::dynamic_business_delete_confirm_page_params_json("demo", std::path::Path::new("apps/dev_docs"));
15241/// ```
15242///
15243/// # Related
15244///
15245/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15246pub fn dynamic_business_delete_confirm_page_params_json(
15247    business_slug: &str,
15248    app_root: &Path,
15249) -> Option<String> {
15250    let mut extra = Map::new();
15251    extra.insert("business_slug".into(), Value::String(business_slug.into()));
15252    extra.insert(
15253        "app_root".into(),
15254        Value::String(app_root.to_string_lossy().into_owned()),
15255    );
15256    page_params_value(&Value::Object(Map::new()), "business-delete-confirm", extra)
15257}
15258
15259/// Builds the invite-accept page parameter document.
15260///
15261/// # Parameters
15262///
15263/// - `token`: Input consumed by [`crate::runtime::json_commands::dynamic_invite_accept_page_params_json`].
15264/// - `error_text`: Input consumed by [`crate::runtime::json_commands::dynamic_invite_accept_page_params_json`].
15265///
15266/// # Returns
15267///
15268/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_invite_accept_page_params_json`] can produce a value and [`None`] otherwise.
15269///
15270/// # Examples
15271///
15272/// ```rust,ignore
15273/// let _result = pharos_native::runtime::json_commands::dynamic_invite_accept_page_params_json(todo!(), todo!());
15274/// ```
15275///
15276/// # Related
15277///
15278/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15279pub fn dynamic_invite_accept_page_params_json(token: &str, error_text: &str) -> Option<String> {
15280    let mut extra = Map::new();
15281    extra.insert("token".into(), Value::String(token.into()));
15282    extra.insert("error".into(), Value::String(error_text.into()));
15283    page_params_value(&Value::Null, "invite-accept", extra)
15284}
15285
15286/// Builds a validated generated-admin operation URL.
15287///
15288/// # Parameters
15289///
15290/// - `base_path`: Input consumed by [`crate::runtime::json_commands::generated_admin_operation_path_dup_business_logic_local`].
15291/// - `operation`: Input consumed by [`crate::runtime::json_commands::generated_admin_operation_path_dup_business_logic_local`].
15292/// - `record_id`: Input consumed by [`crate::runtime::json_commands::generated_admin_operation_path_dup_business_logic_local`].
15293///
15294/// # Returns
15295///
15296/// Returns [`Some`] when [`crate::runtime::json_commands::generated_admin_operation_path_dup_business_logic_local`] can produce a value and [`None`] otherwise.
15297///
15298/// # Examples
15299///
15300/// ```rust,ignore
15301/// let _result = pharos_native::runtime::json_commands::generated_admin_operation_path_dup_business_logic_local("/app", todo!(), todo!());
15302/// ```
15303///
15304/// # Related
15305///
15306/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15307pub fn generated_admin_operation_path_dup_business_logic_local(
15308    base_path: &str,
15309    operation: &str,
15310    record_id: i64,
15311) -> Option<String> {
15312    if operation.is_empty() || record_id <= 0 || base_path.contains(['\r', '\n']) {
15313        return None;
15314    }
15315    Some(format!(
15316        "{}/{}/{}",
15317        base_path.trim_end_matches('/'),
15318        operation,
15319        record_id
15320    ))
15321}
15322
15323/// Builds generated-admin management page parameters from state.
15324///
15325/// # Parameters
15326///
15327/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_page_params_json`].
15328/// - `collection`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_page_params_json`].
15329/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_page_params_json`].
15330///
15331/// # Returns
15332///
15333/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_generated_admin_manage_page_params_json`] can produce a value and [`None`] otherwise.
15334///
15335/// # Examples
15336///
15337/// ```rust,ignore
15338/// let _result = pharos_native::runtime::json_commands::dynamic_generated_admin_manage_page_params_json(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"));
15339/// ```
15340///
15341/// # Related
15342///
15343/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15344pub fn dynamic_generated_admin_manage_page_params_json(
15345    root: &Value,
15346    collection: &str,
15347    app_root: &Path,
15348) -> Option<String> {
15349    let mut extra = Map::new();
15350    extra.insert("collection".into(), Value::String(collection.into()));
15351    extra.insert(
15352        "app_root".into(),
15353        Value::String(app_root.to_string_lossy().into_owned()),
15354    );
15355    extra.insert(
15356        "rows".into(),
15357        Value::Array(bounded_state_array(root, collection).to_vec()),
15358    );
15359    page_params_value(root, "generated-admin-manage", extra)
15360}
15361
15362/// Converts a JSON value to its compact scalar representation.
15363///
15364/// # Parameters
15365///
15366/// - `value`: Input consumed by [`crate::runtime::json_commands::json_value_tostring_dup_runtime_local`].
15367///
15368/// # Returns
15369///
15370/// Returns [`Some`] when [`crate::runtime::json_commands::json_value_tostring_dup_runtime_local`] can produce a value and [`None`] otherwise.
15371///
15372/// # Examples
15373///
15374/// ```rust,ignore
15375/// let _result = pharos_native::runtime::json_commands::json_value_tostring_dup_runtime_local("value");
15376/// ```
15377///
15378/// # Related
15379///
15380/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15381pub fn json_value_tostring_dup_runtime_local(value: &Value) -> Option<String> {
15382    compact(value)
15383}
15384
15385/// Returns a bounded composition string from a surface value.
15386///
15387/// # Parameters
15388///
15389/// - `value`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_composition_string`].
15390///
15391/// # Returns
15392///
15393/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_generated_surface_composition_string`] can produce a value and [`None`] otherwise.
15394///
15395/// # Examples
15396///
15397/// ```rust,ignore
15398/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_composition_string("value");
15399/// ```
15400///
15401/// # Related
15402///
15403/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15404pub fn runtime_generated_surface_composition_string(value: &Value) -> Option<String> {
15405    value
15406        .as_str()
15407        .map(strdup)
15408        .filter(|value| value.len() <= MAX_TEXT_BYTES)
15409}
15410
15411/// Returns the generated delete-button label.
15412///
15413/// # Returns
15414///
15415/// Returns the computed value produced by [`crate::runtime::json_commands::runtime_generated_surface_delete_button_label`].
15416///
15417/// # Examples
15418///
15419/// ```rust,ignore
15420/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_delete_button_label();
15421/// ```
15422///
15423/// # Related
15424///
15425/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15426pub fn runtime_generated_surface_delete_button_label() -> String {
15427    "Delete".to_owned()
15428}
15429
15430/// Converts one display value to escaped text.
15431///
15432/// # Parameters
15433///
15434/// - `value`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_display_value`].
15435///
15436/// # Returns
15437///
15438/// Returns the computed value produced by [`crate::runtime::json_commands::runtime_generated_surface_display_value`].
15439///
15440/// # Examples
15441///
15442/// ```rust,ignore
15443/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_display_value("value");
15444/// ```
15445///
15446/// # Related
15447///
15448/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15449pub fn runtime_generated_surface_display_value(value: &Value) -> String {
15450    html_escape_text(&value_to_text(value))
15451}
15452
15453/// Returns a generated field label from a field declaration.
15454///
15455/// # Parameters
15456///
15457/// - `field`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_label`].
15458///
15459/// # Returns
15460///
15461/// Returns the computed value produced by [`crate::runtime::json_commands::runtime_generated_surface_label`].
15462///
15463/// # Examples
15464///
15465/// ```rust,ignore
15466/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_label("field");
15467/// ```
15468///
15469/// # Related
15470///
15471/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15472pub fn runtime_generated_surface_label(field: &Value) -> String {
15473    field
15474        .get("label")
15475        .and_then(Value::as_str)
15476        .or_else(|| field.get("field_id").and_then(Value::as_str))
15477        .map(strdup)
15478        .unwrap_or_default()
15479}
15480
15481/// Takes a text buffer and leaves it empty.
15482///
15483/// # Parameters
15484///
15485/// - `buffer`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_take`].
15486///
15487/// # Returns
15488///
15489/// Returns the computed value produced by [`crate::runtime::json_commands::runtime_text_buffer_take`].
15490///
15491/// # Examples
15492///
15493/// ```rust,ignore
15494/// let _result = pharos_native::runtime::json_commands::runtime_text_buffer_take(&mut []);
15495/// ```
15496///
15497/// # Related
15498///
15499/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15500pub fn runtime_text_buffer_take(buffer: &mut String) -> String {
15501    std::mem::take(buffer)
15502}
15503
15504/// Builds appointments page parameters from a state root.
15505///
15506/// # Parameters
15507///
15508/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_from_root_json`].
15509/// - `user_id`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_from_root_json`].
15510/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_from_root_json`].
15511///
15512/// # Returns
15513///
15514/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_appointments_page_params_from_root_json`] can produce a value and [`None`] otherwise.
15515///
15516/// # Examples
15517///
15518/// ```rust,ignore
15519/// let _result = pharos_native::runtime::json_commands::dynamic_appointments_page_params_from_root_json(std::path::Path::new("."), 1, std::path::Path::new("apps/dev_docs"));
15520/// ```
15521///
15522/// # Related
15523///
15524/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15525pub fn dynamic_appointments_page_params_from_root_json(
15526    root: &Value,
15527    user_id: i64,
15528    app_root: &Path,
15529) -> Option<String> {
15530    if user_id <= 0 {
15531        return None;
15532    }
15533    let mut rows_html = String::new();
15534    for row in bounded_state_array(root, "appointments")
15535        .iter()
15536        .filter(|row| row_i64_value(row, "user_id") == Some(user_id))
15537    {
15538        let service = row_i64_value(row, "service_id")
15539            .and_then(|id| state_row_by_i64(root, "services", "id", id));
15540        let business = row_i64_value(row, "business_id")
15541            .and_then(|id| state_row_by_i64(root, "businesses", "id", id));
15542        let service_name = service
15543            .and_then(|value| value.get("name"))
15544            .map(value_to_text)
15545            .filter(|value| !value.is_empty())
15546            .unwrap_or_else(|| "Appointment".to_owned());
15547        let business_name = business
15548            .and_then(|value| value.get("name"))
15549            .map(value_to_text)
15550            .filter(|value| !value.is_empty())
15551            .unwrap_or_else(|| "Business".to_owned());
15552        let business_slug = business
15553            .and_then(|value| value.get("slug"))
15554            .map(value_to_text)
15555            .unwrap_or_default();
15556        let (date, time) = row_date_time(row);
15557        let status = row
15558            .get("status")
15559            .map(value_to_text)
15560            .filter(|value| !value.is_empty())
15561            .unwrap_or_else(|| "scheduled".to_owned());
15562        let payment_status = row
15563            .get("payment_status")
15564            .map(value_to_text)
15565            .unwrap_or_default();
15566        let meta_line_one = if date.is_empty() && time.is_empty() {
15567            business_name.clone()
15568        } else {
15569            format!(
15570                "{} at {}",
15571                date,
15572                formatted_clock_time_business_logic_local(&time)
15573            )
15574        };
15575        let meta_line_two = if payment_status.is_empty() {
15576            business_name
15577        } else {
15578            format!("{business_name} · Payment: {payment_status}")
15579        };
15580        rows_html.push_str(&render_fragment_with_params(
15581            app_root,
15582            "templates/shared/fragments/appointment_row.html",
15583            Map::from_iter([
15584                ("service_name".to_owned(), Value::String(service_name)),
15585                ("status_value".to_owned(), Value::String(status)),
15586                ("meta_line_one".to_owned(), Value::String(meta_line_one)),
15587                (
15588                    "meta_line_one_style".to_owned(),
15589                    Value::String(String::new()),
15590                ),
15591                ("meta_line_two".to_owned(), Value::String(meta_line_two)),
15592                (
15593                    "meta_line_two_style".to_owned(),
15594                    Value::String(String::new()),
15595                ),
15596                ("tertiary_line".to_owned(), Value::String(String::new())),
15597                (
15598                    "tertiary_line_style".to_owned(),
15599                    Value::String("display:none;".to_owned()),
15600                ),
15601                (
15602                    "notes_text".to_owned(),
15603                    Value::String(row.get("notes").map(value_to_text).unwrap_or_default()),
15604                ),
15605                (
15606                    "notes_style".to_owned(),
15607                    Value::String(
15608                        if row
15609                            .get("notes")
15610                            .map(value_to_text)
15611                            .unwrap_or_default()
15612                            .is_empty()
15613                        {
15614                            "display:none;".to_owned()
15615                        } else {
15616                            String::new()
15617                        },
15618                    ),
15619                ),
15620                (
15621                    "detail_path".to_owned(),
15622                    Value::String(if business_slug.is_empty() {
15623                        "/appointments/".to_owned()
15624                    } else {
15625                        format!("/b/{business_slug}/")
15626                    }),
15627                ),
15628                (
15629                    "detail_link_style".to_owned(),
15630                    Value::String("display:none;".to_owned()),
15631                ),
15632                (
15633                    "request_cancel_path".to_owned(),
15634                    Value::String(format!(
15635                        "/appointments/{}/request-cancel/",
15636                        row_i64_value(row, "id").unwrap_or(0)
15637                    )),
15638                ),
15639                (
15640                    "request_cancel_style".to_owned(),
15641                    Value::String("display:none;".to_owned()),
15642                ),
15643                (
15644                    "request_cancel_button_ui_html".to_owned(),
15645                    Value::String(String::new()),
15646                ),
15647                (
15648                    "complete_path".to_owned(),
15649                    Value::String(format!(
15650                        "/appointments/{}/complete/",
15651                        row_i64_value(row, "id").unwrap_or(0)
15652                    )),
15653                ),
15654                (
15655                    "complete_style".to_owned(),
15656                    Value::String("display:none;".to_owned()),
15657                ),
15658                (
15659                    "complete_button_ui_html".to_owned(),
15660                    Value::String(String::new()),
15661                ),
15662                (
15663                    "cancel_path".to_owned(),
15664                    Value::String(format!(
15665                        "/appointments/{}/cancel/",
15666                        row_i64_value(row, "id").unwrap_or(0)
15667                    )),
15668                ),
15669                (
15670                    "cancel_style".to_owned(),
15671                    Value::String("display:none;".to_owned()),
15672                ),
15673                (
15674                    "cancel_button_ui_html".to_owned(),
15675                    Value::String(String::new()),
15676                ),
15677            ]),
15678        )?);
15679    }
15680    if rows_html.is_empty() {
15681        rows_html = render_fragment_with_params(
15682            app_root,
15683            "templates/appointments/fragments/appointments_empty_manage.html",
15684            Map::new(),
15685        )?;
15686    }
15687    compact(&Value::Object(Map::from_iter([
15688        (
15689            "heading".to_owned(),
15690            Value::String("Appointments".to_owned()),
15691        ),
15692        ("appointment_items".to_owned(), Value::String(rows_html)),
15693        ("tips_style".to_owned(), Value::String(String::new())),
15694    ])))
15695}
15696
15697/// Loads appointments page parameters from a state file.
15698///
15699/// # Parameters
15700///
15701/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_json`].
15702/// - `user_id`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_json`].
15703/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_appointments_page_params_json`].
15704///
15705/// # Returns
15706///
15707/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_appointments_page_params_json`] can produce a value and [`None`] otherwise.
15708///
15709/// # Examples
15710///
15711/// ```rust,ignore
15712/// let _result = pharos_native::runtime::json_commands::dynamic_appointments_page_params_json(todo!(), 1, std::path::Path::new("apps/dev_docs"));
15713/// ```
15714///
15715/// # Related
15716///
15717/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15718pub fn dynamic_appointments_page_params_json(
15719    state_path: &Path,
15720    user_id: i64,
15721    app_root: &Path,
15722) -> Option<String> {
15723    dynamic_appointments_page_params_from_root_json(
15724        &json_doc_load_file(state_path)?,
15725        user_id,
15726        app_root,
15727    )
15728}
15729
15730/// Builds the booking form parameter document.
15731///
15732/// # Returns
15733///
15734/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_booking_form_page_params_json`] can produce a value and [`None`] otherwise.
15735///
15736/// # Examples
15737///
15738/// ```rust,ignore
15739/// let _result = pharos_native::runtime::json_commands::dynamic_booking_form_page_params_json();
15740/// ```
15741///
15742/// # Related
15743///
15744/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15745pub fn dynamic_booking_form_page_params_json() -> Option<String> {
15746    page_params_value(&Value::Null, "booking-form", Map::new())
15747}
15748
15749/// Builds bookings page parameters from state.
15750///
15751/// # Parameters
15752///
15753/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_bookings_page_params_json`].
15754/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_bookings_page_params_json`].
15755/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_bookings_page_params_json`].
15756///
15757/// # Returns
15758///
15759/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_bookings_page_params_json`] can produce a value and [`None`] otherwise.
15760///
15761/// # Examples
15762///
15763/// ```rust,ignore
15764/// let _result = pharos_native::runtime::json_commands::dynamic_bookings_page_params_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
15765/// ```
15766///
15767/// # Related
15768///
15769/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15770pub fn dynamic_bookings_page_params_json(
15771    root: &Value,
15772    business_slug: &str,
15773    app_root: &Path,
15774) -> Option<String> {
15775    let mut extra = Map::new();
15776    extra.insert("business_slug".into(), Value::String(business_slug.into()));
15777    extra.insert(
15778        "app_root".into(),
15779        Value::String(app_root.to_string_lossy().into_owned()),
15780    );
15781    extra.insert(
15782        "bookings".into(),
15783        Value::Array(bounded_state_array(root, "bookings").to_vec()),
15784    );
15785    page_params_value(root, "bookings", extra)
15786}
15787
15788pub fn dynamic_user_bookings_page_params_from_root_json(
15789    root: &Value,
15790    user_id: i64,
15791    app_root: &Path,
15792) -> Option<String> {
15793    if user_id <= 0 {
15794        return None;
15795    }
15796    let mut rows_html = String::new();
15797    for row in bounded_state_array(root, "bookings")
15798        .iter()
15799        .filter(|row| row_i64_value(row, "user_id") == Some(user_id))
15800    {
15801        let (date, time) = row_date_time(row);
15802        rows_html.push_str(&render_fragment_with_params(
15803            app_root,
15804            "templates/bookings/fragments/booking_row.html",
15805            Map::from_iter([
15806                (
15807                    "booking_title".to_owned(),
15808                    Value::String(
15809                        row.get("title")
15810                            .map(value_to_text)
15811                            .filter(|value| !value.is_empty())
15812                            .unwrap_or_else(|| "Booking".to_owned()),
15813                    ),
15814                ),
15815                (
15816                    "status_value".to_owned(),
15817                    Value::String(
15818                        row.get("status")
15819                            .map(value_to_text)
15820                            .filter(|value| !value.is_empty())
15821                            .unwrap_or_else(|| "confirmed".to_owned()),
15822                    ),
15823                ),
15824                ("date_value".to_owned(), Value::String(date)),
15825                (
15826                    "time_value".to_owned(),
15827                    Value::String(formatted_clock_time_business_logic_local(&time)),
15828                ),
15829            ]),
15830        )?);
15831    }
15832    if rows_html.is_empty() {
15833        rows_html = render_fragment_with_params(
15834            app_root,
15835            "templates/bookings/bookings_empty.html",
15836            Map::new(),
15837        )?;
15838    }
15839    compact(&Value::Object(Map::from_iter([
15840        (
15841            "create_path".to_owned(),
15842            Value::String("/bookings/new/".to_owned()),
15843        ),
15844        (
15845            "error_style".to_owned(),
15846            Value::String("display:none;".to_owned()),
15847        ),
15848        ("error_message".to_owned(), Value::String(String::new())),
15849        ("booking_rows_html".to_owned(), Value::String(rows_html)),
15850    ])))
15851}
15852
15853/// Builds the business admin page parameter document.
15854///
15855/// # Parameters
15856///
15857/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_page_params_json`].
15858/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_page_params_json`].
15859/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_page_params_json`].
15860///
15861/// # Returns
15862///
15863/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_admin_page_params_json`] can produce a value and [`None`] otherwise.
15864///
15865/// # Examples
15866///
15867/// ```rust,ignore
15868/// let _result = pharos_native::runtime::json_commands::dynamic_business_admin_page_params_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
15869/// ```
15870///
15871/// # Related
15872///
15873/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15874pub fn dynamic_business_admin_page_params_json(
15875    root: &Value,
15876    business_slug: &str,
15877    app_root: &Path,
15878) -> Option<String> {
15879    dynamic_bookings_page_params_json(root, business_slug, app_root)
15880}
15881
15882/// Builds the business calendar page parameters.
15883///
15884/// # Parameters
15885///
15886/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15887/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15888/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15889/// - `year`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15890/// - `month`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15891/// - `date`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15892///
15893/// # Returns
15894///
15895/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`] can produce a value and [`None`] otherwise.
15896///
15897/// # Performance
15898///
15899/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json`].
15900///
15901/// # Examples
15902///
15903/// ```rust,ignore
15904/// let _result = pharos_native::runtime::json_commands::dynamic_business_calendar_page_params_from_root_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
15905/// ```
15906///
15907/// # Related
15908///
15909/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15910pub fn dynamic_business_calendar_page_params_from_root_json(
15911    root: &Value,
15912    business_slug: &str,
15913    app_root: &Path,
15914    year: Option<&str>,
15915    month: Option<&str>,
15916    date: Option<&str>,
15917) -> Option<String> {
15918    let mut extra = Map::new();
15919    for (key, value) in [
15920        ("business_slug", business_slug),
15921        ("year", year.unwrap_or_default()),
15922        ("month", month.unwrap_or_default()),
15923        ("date", date.unwrap_or_default()),
15924    ] {
15925        extra.insert(key.into(), Value::String(value.into()));
15926    }
15927    extra.insert(
15928        "app_root".into(),
15929        Value::String(app_root.to_string_lossy().into_owned()),
15930    );
15931    extra.insert(
15932        "appointments".into(),
15933        Value::Array(bounded_state_array(root, "appointments").to_vec()),
15934    );
15935    page_params_value(root, "business-calendar", extra)
15936}
15937
15938/// Loads business calendar parameters from state.
15939///
15940/// # Parameters
15941///
15942/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15943/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15944/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15945/// - `year`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15946/// - `month`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15947/// - `date`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`].
15948///
15949/// # Returns
15950///
15951/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_calendar_page_params_json`] can produce a value and [`None`] otherwise.
15952///
15953/// # Examples
15954///
15955/// ```rust,ignore
15956/// let _result = pharos_native::runtime::json_commands::dynamic_business_calendar_page_params_json(todo!(), "demo", std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
15957/// ```
15958///
15959/// # Related
15960///
15961/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
15962pub fn dynamic_business_calendar_page_params_json(
15963    state_path: &Path,
15964    business_slug: &str,
15965    app_root: &Path,
15966    year: Option<&str>,
15967    month: Option<&str>,
15968    date: Option<&str>,
15969) -> Option<String> {
15970    dynamic_business_calendar_page_params_from_root_json(
15971        &json_doc_load_file(state_path)?,
15972        business_slug,
15973        app_root,
15974        year,
15975        month,
15976        date,
15977    )
15978}
15979
15980/// Renders icon button fragment.
15981fn render_icon_button_fragment(
15982    app_root: &Path,
15983    id: &str,
15984    button_type: &str,
15985    class_name: &str,
15986    attributes_html: &str,
15987    content_fragment: &str,
15988    content_params: serde_json::Map<String, Value>,
15989) -> Option<String> {
15990    let content_html = render_fragment_with_params(app_root, content_fragment, content_params)?;
15991    render_fragment_with_params(
15992        app_root,
15993        "templates/shared/fragments/ui_button.html",
15994        serde_json::Map::from_iter([
15995            ("id".to_owned(), Value::String(id.to_owned())),
15996            (
15997                "button_type".to_owned(),
15998                Value::String(button_type.to_owned()),
15999            ),
16000            (
16001                "class_name".to_owned(),
16002                Value::String(class_name.to_owned()),
16003            ),
16004            (
16005                "attributes_html".to_owned(),
16006                Value::String(attributes_html.to_owned()),
16007            ),
16008            ("content_html".to_owned(), Value::String(content_html)),
16009        ]),
16010    )
16011}
16012
16013/// Renders compact input fragment.
16014fn render_compact_input_fragment(
16015    app_root: &Path,
16016    id: &str,
16017    input_type: &str,
16018    name: &str,
16019    label: &str,
16020    value: &str,
16021    class_name: &str,
16022    attributes_html: &str,
16023) -> Option<String> {
16024    render_fragment_with_params(
16025        app_root,
16026        "templates/shared/fragments/ui_input.html",
16027        serde_json::Map::from_iter([
16028            ("id".to_owned(), Value::String(id.to_owned())),
16029            (
16030                "input_type".to_owned(),
16031                Value::String(input_type.to_owned()),
16032            ),
16033            ("name".to_owned(), Value::String(name.to_owned())),
16034            ("label".to_owned(), Value::String(label.to_owned())),
16035            (
16036                "label_class".to_owned(),
16037                Value::String("sr-only".to_owned()),
16038            ),
16039            (
16040                "class_name".to_owned(),
16041                Value::String(class_name.to_owned()),
16042            ),
16043            ("value".to_owned(), Value::String(value.to_owned())),
16044            (
16045                "attributes_html".to_owned(),
16046                Value::String(attributes_html.to_owned()),
16047            ),
16048            ("help_html".to_owned(), Value::String(String::new())),
16049        ]),
16050    )
16051}
16052
16053/// Renders compact select fragment.
16054fn render_compact_select_fragment(
16055    app_root: &Path,
16056    id: &str,
16057    name: &str,
16058    label: &str,
16059    class_name: &str,
16060    attributes_html: &str,
16061    options_html: String,
16062) -> Option<String> {
16063    render_fragment_with_params(
16064        app_root,
16065        "templates/shared/fragments/ui_select.html",
16066        serde_json::Map::from_iter([
16067            ("id".to_owned(), Value::String(id.to_owned())),
16068            ("name".to_owned(), Value::String(name.to_owned())),
16069            ("label".to_owned(), Value::String(label.to_owned())),
16070            (
16071                "label_class".to_owned(),
16072                Value::String("sr-only".to_owned()),
16073            ),
16074            (
16075                "class_name".to_owned(),
16076                Value::String(class_name.to_owned()),
16077            ),
16078            (
16079                "attributes_html".to_owned(),
16080                Value::String(attributes_html.to_owned()),
16081            ),
16082            ("options_html".to_owned(), Value::String(options_html)),
16083            ("help_html".to_owned(), Value::String(String::new())),
16084        ]),
16085    )
16086}
16087
16088/// Renders hidden input fragment.
16089fn render_hidden_input_fragment(
16090    app_root: &Path,
16091    id: &str,
16092    name: &str,
16093    value: &str,
16094) -> Option<String> {
16095    render_fragment_with_params(
16096        app_root,
16097        "templates/shared/fragments/ui_hidden_input.html",
16098        serde_json::Map::from_iter([
16099            ("id".to_owned(), Value::String(id.to_owned())),
16100            ("name".to_owned(), Value::String(name.to_owned())),
16101            ("value".to_owned(), Value::String(value.to_owned())),
16102            ("attributes_html".to_owned(), Value::String(String::new())),
16103        ]),
16104    )
16105}
16106
16107/// Renders textarea fragment.
16108fn render_textarea_fragment(
16109    app_root: &Path,
16110    id: &str,
16111    name: &str,
16112    label: &str,
16113    value: &str,
16114    class_name: &str,
16115    attributes_html: &str,
16116) -> Option<String> {
16117    render_fragment_with_params(
16118        app_root,
16119        "templates/shared/fragments/ui_textarea.html",
16120        serde_json::Map::from_iter([
16121            ("id".to_owned(), Value::String(id.to_owned())),
16122            ("name".to_owned(), Value::String(name.to_owned())),
16123            ("label".to_owned(), Value::String(label.to_owned())),
16124            (
16125                "label_class".to_owned(),
16126                Value::String("sr-only".to_owned()),
16127            ),
16128            (
16129                "class_name".to_owned(),
16130                Value::String(class_name.to_owned()),
16131            ),
16132            ("value".to_owned(), Value::String(value.to_owned())),
16133            (
16134                "attributes_html".to_owned(),
16135                Value::String(attributes_html.to_owned()),
16136            ),
16137            ("help_html".to_owned(), Value::String(String::new())),
16138        ]),
16139    )
16140}
16141
16142/// Renders day select options.
16143fn render_day_select_options(
16144    app_root: &Path,
16145    selected: &str,
16146    include_groups: bool,
16147) -> Option<String> {
16148    let mut options_html = String::new();
16149    if include_groups {
16150        for (value, label) in [("Weekdays", "Weekdays"), ("Weekends", "Weekends")] {
16151            options_html.push_str(&render_fragment_with_params(
16152                app_root,
16153                "templates/shared/fragments/select_option.html",
16154                Map::from_iter([
16155                    ("option_value".to_owned(), Value::String(value.to_owned())),
16156                    ("option_label".to_owned(), Value::String(label.to_owned())),
16157                    (
16158                        "selected_attr".to_owned(),
16159                        Value::String(if selected == value { " selected" } else { "" }.to_owned()),
16160                    ),
16161                ]),
16162            )?);
16163        }
16164    }
16165    for day in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] {
16166        options_html.push_str(&render_fragment_with_params(
16167            app_root,
16168            "templates/shared/fragments/select_option.html",
16169            Map::from_iter([
16170                ("option_value".to_owned(), Value::String(day.to_owned())),
16171                ("option_label".to_owned(), Value::String(day.to_owned())),
16172                (
16173                    "selected_attr".to_owned(),
16174                    Value::String(if selected == day { " selected" } else { "" }.to_owned()),
16175                ),
16176            ]),
16177        )?);
16178    }
16179    Some(options_html)
16180}
16181
16182/// Performs business day matches group.
16183fn business_day_matches_group(day: &str, selected: &str) -> bool {
16184    match selected {
16185        "Weekdays" => matches!(day, "Mon" | "Tue" | "Wed" | "Thu" | "Fri"),
16186        "Weekends" => matches!(day, "Sat" | "Sun"),
16187        _ => day == selected,
16188    }
16189}
16190
16191/// Performs dynamic business admin service cards HTML.
16192///
16193/// # Parameters
16194///
16195/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_service_cards_html`].
16196/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_service_cards_html`].
16197/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_admin_service_cards_html`].
16198///
16199/// # Returns
16200///
16201/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_admin_service_cards_html`] can produce a value and [`None`] otherwise.
16202///
16203/// # Performance
16204///
16205/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_business_admin_service_cards_html`].
16206///
16207/// # Examples
16208///
16209/// ```rust,ignore
16210/// let _result = pharos_native::runtime::json_commands::dynamic_business_admin_service_cards_html(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
16211/// ```
16212///
16213/// # Related
16214///
16215/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
16216pub fn dynamic_business_admin_service_cards_html(
16217    root: &Value,
16218    business_slug: &str,
16219    app_root: &Path,
16220) -> Option<String> {
16221    let business = bounded_state_array(root, "businesses")
16222        .iter()
16223        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
16224    let business_id = business.get("id").and_then(Value::as_i64)?;
16225    let mut services: Vec<&Value> = bounded_state_array(root, "services")
16226        .iter()
16227        .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
16228        .filter(|row| row.get("is_active").and_then(Value::as_bool) != Some(false))
16229        .collect();
16230    services.sort_by_key(|row| {
16231        row.get("sort_order")
16232            .and_then(Value::as_i64)
16233            .filter(|value| *value > 0)
16234            .unwrap_or_else(|| row.get("id").and_then(Value::as_i64).unwrap_or(0))
16235    });
16236    let mut output = String::new();
16237    for service in services {
16238        let service_id = service.get("id").and_then(Value::as_i64)?;
16239        let service_name = service.get("name").map(value_to_text).unwrap_or_default();
16240        let description = service
16241            .get("description")
16242            .map(value_to_text)
16243            .unwrap_or_default();
16244        let description_html = if description.is_empty() {
16245            String::new()
16246        } else {
16247            render_fragment_with_params(
16248                app_root,
16249                "templates/businesses/fragments/business_admin_service_description.html",
16250                Map::from_iter([("description".to_owned(), Value::String(description.clone()))]),
16251            )?
16252        };
16253        let order_value = service
16254            .get("sort_order")
16255            .and_then(Value::as_i64)
16256            .filter(|value| *value > 0)
16257            .unwrap_or(service_id);
16258        let summary = format!(
16259            "Order {} · ${} · {} min",
16260            order_value,
16261            service.get("cost").map(value_to_text).unwrap_or_default(),
16262            service
16263                .get("duration_minutes")
16264                .map(value_to_text)
16265                .filter(|value| !value.is_empty())
16266                .unwrap_or_else(|| "45".to_owned())
16267        );
16268        let booking_options: Vec<String> = service
16269            .get("booking_options")
16270            .and_then(Value::as_array)
16271            .map(|rows| {
16272                rows.iter()
16273                    .filter_map(|row| {
16274                        let label = row
16275                            .get("label")
16276                            .or_else(|| row.get("name"))
16277                            .map(value_to_text)
16278                            .unwrap_or_default();
16279                        if label.is_empty() {
16280                            return None;
16281                        }
16282                        let cost = row.get("cost").map(value_to_text).unwrap_or_default();
16283                        Some(if cost.is_empty() {
16284                            label
16285                        } else {
16286                            format!("{label} ${cost}")
16287                        })
16288                    })
16289                    .collect()
16290            })
16291            .unwrap_or_default();
16292        let booking_options_html = if booking_options.is_empty() {
16293            String::new()
16294        } else {
16295            render_fragment_with_params(
16296                app_root,
16297                "templates/businesses/fragments/business_admin_service_options.html",
16298                Map::from_iter([(
16299                    "options".to_owned(),
16300                    Value::String(booking_options.join(", ")),
16301                )]),
16302            )?
16303        };
16304        let assigned_technician_ids: Vec<String> = service
16305            .get("assigned_technician_ids")
16306            .or_else(|| service.get("technician_ids"))
16307            .and_then(Value::as_array)
16308            .map(|rows| rows.iter().map(value_to_text).collect())
16309            .unwrap_or_default();
16310        let technician_names: Vec<String> = bounded_state_array(root, "technicians")
16311            .iter()
16312            .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
16313            .filter(|row| {
16314                assigned_technician_ids
16315                    .iter()
16316                    .any(|id| row.get("id").map(value_to_text).as_deref() == Some(id.as_str()))
16317            })
16318            .filter_map(|row| {
16319                row.get("name")
16320                    .map(value_to_text)
16321                    .filter(|name| !name.is_empty())
16322            })
16323            .collect();
16324        let technicians_html = if technician_names.is_empty() {
16325            String::new()
16326        } else {
16327            render_fragment_with_params(
16328                app_root,
16329                "templates/businesses/fragments/business_admin_service_technicians.html",
16330                Map::from_iter([(
16331                    "technicians".to_owned(),
16332                    Value::String(technician_names.join(", ")),
16333                )]),
16334            )?
16335        };
16336        let image_url = service
16337            .get("image_url")
16338            .and_then(Value::as_str)
16339            .unwrap_or_default();
16340        let image_html = if image_url.is_empty() {
16341            service_visual_html(
16342                app_root,
16343                None,
16344                &service_name,
16345                service.get("primary_color").and_then(Value::as_str),
16346            )?
16347        } else {
16348            render_fragment_with_params(
16349                app_root,
16350                "templates/businesses/fragments/business_admin_service_image.html",
16351                Map::from_iter([
16352                    ("image_url".to_owned(), Value::String(image_url.to_owned())),
16353                    ("image_alt".to_owned(), Value::String(service_name.clone())),
16354                ]),
16355            )?
16356        };
16357        output.push_str(&render_fragment_with_params(
16358            app_root,
16359            "templates/businesses/fragments/business_admin_service_card.html",
16360            serde_json::Map::from_iter([
16361                (
16362                    "delete_path".to_owned(),
16363                    Value::String(format!(
16364                        "/businesses/{business_slug}/services/{service_id}/delete/"
16365                    )),
16366                ),
16367                (
16368                    "edit_path".to_owned(),
16369                    Value::String(format!(
16370                        "/businesses/{business_slug}/services/{service_id}/edit/"
16371                    )),
16372                ),
16373                ("image_html".to_owned(), Value::String(image_html)),
16374                ("service_name".to_owned(), Value::String(service_name)),
16375                ("service_summary".to_owned(), Value::String(summary)),
16376                (
16377                    "service_description_html".to_owned(),
16378                    Value::String(description_html),
16379                ),
16380                (
16381                    "booking_options_html".to_owned(),
16382                    Value::String(booking_options_html),
16383                ),
16384                (
16385                    "technicians_html".to_owned(),
16386                    Value::String(technicians_html),
16387                ),
16388            ]),
16389        )?);
16390    }
16391    Some(output)
16392}
16393
16394/// Builds business admin page params from a loaded state root.
16395///
16396/// # Parameters
16397///
16398/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`].
16399/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`].
16400/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`].
16401/// - `target`: Input consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`].
16402///
16403/// # Returns
16404///
16405/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`] can produce a value and [`None`] otherwise.
16406///
16407/// # Performance
16408///
16409/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_generated_admin_manage_sections_html`].
16410///
16411/// # Examples
16412///
16413/// ```rust,ignore
16414/// let _result = pharos_native::runtime::json_commands::dynamic_generated_admin_manage_sections_html(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"), "/");
16415/// ```
16416///
16417/// # Related
16418///
16419/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
16420pub fn dynamic_generated_admin_manage_sections_html(
16421    root: &Value,
16422    business_slug: &str,
16423    app_root: &Path,
16424    target: &str,
16425) -> Option<String> {
16426    let services_path = format!("/businesses/{business_slug}/services/");
16427    let availability_path = format!("/businesses/{business_slug}/availability/");
16428    if target.contains("/availability/") {
16429        let availability_rows_html =
16430            dynamic_render_business_admin_availability_rows_html(root, business_slug, app_root)?;
16431        let availability_body_html = render_fragment_with_params(
16432            app_root,
16433            "templates/businesses/fragments/business_admin_availability_body.html",
16434            serde_json::Map::from_iter([
16435                (
16436                    "availability_rows_html".to_owned(),
16437                    Value::String(availability_rows_html),
16438                ),
16439                (
16440                    "availability_create_path".to_owned(),
16441                    Value::String(format!("/businesses/{business_slug}/availability/new/")),
16442                ),
16443                (
16444                    "business_admin_availability_day_select_ui_html".to_owned(),
16445                    Value::String(render_compact_select_fragment(
16446                        app_root,
16447                        &format!("availability-manage-day-{business_slug}"),
16448                        "day_of_week",
16449                        "Day",
16450                        "form-control form-control-compact availability-inline-input",
16451                        " autocomplete=\"off\"",
16452                        render_day_select_options(app_root, "Mon", true)?,
16453                    )?),
16454                ),
16455                (
16456                    "business_admin_availability_start_time_input_ui_html".to_owned(),
16457                    Value::String(render_compact_input_fragment(
16458                        app_root,
16459                        &format!("availability-manage-start-{business_slug}"),
16460                        "time",
16461                        "start_time",
16462                        "Start",
16463                        "09:00",
16464                        "form-control form-control-compact availability-inline-input",
16465                        " autocomplete=\"off\"",
16466                    )?),
16467                ),
16468                (
16469                    "business_admin_availability_end_time_input_ui_html".to_owned(),
16470                    Value::String(render_compact_input_fragment(
16471                        app_root,
16472                        &format!("availability-manage-end-{business_slug}"),
16473                        "time",
16474                        "end_time",
16475                        "End",
16476                        "17:00",
16477                        "form-control form-control-compact availability-inline-input",
16478                        " autocomplete=\"off\"",
16479                    )?),
16480                ),
16481                (
16482                    "business_admin_availability_submit_button_ui_html".to_owned(),
16483                    Value::String(render_icon_button_fragment(
16484                        app_root,
16485                        &format!("availability-manage-submit-{business_slug}"),
16486                        "submit",
16487                        "btn btn-success btn-icon btn-icon-lg business-admin-save-button",
16488                        "",
16489                        "templates/shared/fragments/ui_content_apply_hours.html",
16490                        serde_json::Map::new(),
16491                    )?),
16492                ),
16493            ]),
16494        )?;
16495        return render_fragment_with_params(
16496            app_root,
16497            "templates/businesses/fragments/business_admin_availability_manage.html",
16498            serde_json::Map::from_iter([
16499                ("services_path".to_owned(), Value::String(services_path)),
16500                (
16501                    "availability_body_html".to_owned(),
16502                    Value::String(availability_body_html),
16503                ),
16504            ]),
16505        );
16506    }
16507
16508    let business = bounded_state_array(root, "businesses")
16509        .iter()
16510        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
16511    let business_id = business.get("id").and_then(Value::as_i64)?;
16512    let service_rows_html =
16513        dynamic_business_admin_service_cards_html(root, business_slug, app_root)?;
16514    let service_create_technician_rows_html =
16515        technician_checkboxes_html(app_root, root, business_id, 0, "No technicians yet.", true)?;
16516    let services_body_html = render_fragment_with_params(
16517        app_root,
16518        "templates/businesses/fragments/business_admin_services_body.html",
16519        serde_json::Map::from_iter([
16520            (
16521                "service_rows_html".to_owned(),
16522                Value::String(service_rows_html),
16523            ),
16524            (
16525                "service_create_path".to_owned(),
16526                Value::String(format!("/businesses/{business_slug}/services/new/")),
16527            ),
16528            (
16529                "business_admin_service_name_input_ui_html".to_owned(),
16530                Value::String(render_compact_input_fragment(
16531                    app_root,
16532                    &format!("service-manage-name-{business_slug}"),
16533                    "text",
16534                    "name",
16535                    "Service name",
16536                    "",
16537                    "form-control",
16538                    " required",
16539                )?),
16540            ),
16541            (
16542                "business_admin_service_cost_input_ui_html".to_owned(),
16543                Value::String(render_compact_input_fragment(
16544                    app_root,
16545                    &format!("service-manage-cost-{business_slug}"),
16546                    "number",
16547                    "cost",
16548                    "Cost",
16549                    "",
16550                    "form-control",
16551                    " min=\"0\" step=\"0.01\"",
16552                )?),
16553            ),
16554            (
16555                "business_admin_service_duration_input_ui_html".to_owned(),
16556                Value::String(render_compact_input_fragment(
16557                    app_root,
16558                    &format!("service-manage-duration-{business_slug}"),
16559                    "number",
16560                    "duration_minutes",
16561                    "Duration",
16562                    "45",
16563                    "form-control",
16564                    " min=\"1\" step=\"1\"",
16565                )?),
16566            ),
16567            (
16568                "business_admin_service_sort_order_select_ui_html".to_owned(),
16569                Value::String(render_compact_select_fragment(
16570                    app_root,
16571                    &format!("service-manage-order-{business_slug}"),
16572                    "sort_order",
16573                    "Order",
16574                    "form-control",
16575                    "",
16576                    service_sort_order_options_html(app_root, root, business_id, 0, true)?,
16577                )?),
16578            ),
16579            (
16580                "business_admin_service_description_textarea_ui_html".to_owned(),
16581                Value::String(render_textarea_fragment(
16582                    app_root,
16583                    &format!("service-manage-description-{business_slug}"),
16584                    "description",
16585                    "Description",
16586                    "",
16587                    "form-control",
16588                    " rows=\"4\" aria-label=\"Description\"",
16589                )?),
16590            ),
16591            (
16592                "business_admin_service_image_input_ui_html".to_owned(),
16593                Value::String(render_fragment_with_params(
16594                    app_root,
16595                    "templates/shared/fragments/ui_input.html",
16596                    serde_json::Map::from_iter([
16597                        (
16598                            "id".to_owned(),
16599                            Value::String("service-create-image".to_owned()),
16600                        ),
16601                        ("input_type".to_owned(), Value::String("file".to_owned())),
16602                        ("name".to_owned(), Value::String("service_image".to_owned())),
16603                        (
16604                            "label".to_owned(),
16605                            Value::String("Service image".to_owned()),
16606                        ),
16607                        (
16608                            "label_class".to_owned(),
16609                            Value::String("sr-only".to_owned()),
16610                        ),
16611                        ("class_name".to_owned(), Value::String(String::new())),
16612                        ("value".to_owned(), Value::String(String::new())),
16613                        (
16614                            "attributes_html".to_owned(),
16615                            Value::String(" accept=\"image/*\" hidden".to_owned()),
16616                        ),
16617                        ("help_html".to_owned(), Value::String(String::new())),
16618                    ]),
16619                )?),
16620            ),
16621            (
16622                "business_admin_service_submit_button_ui_html".to_owned(),
16623                Value::String(render_icon_button_fragment(
16624                    app_root,
16625                    &format!("service-manage-submit-{business_slug}"),
16626                    "submit",
16627                    "btn btn-success btn-icon btn-icon-lg business-admin-save-button",
16628                    " title=\"Save Service\" aria-label=\"Save Service\"",
16629                    "templates/shared/fragments/ui_content_save_service.html",
16630                    serde_json::Map::new(),
16631                )?),
16632            ),
16633            (
16634                "service_create_technicians_empty_style".to_owned(),
16635                Value::String("display:none;".to_owned()),
16636            ),
16637            (
16638                "service_create_technicians_empty_message".to_owned(),
16639                Value::String("No technicians yet.".to_owned()),
16640            ),
16641            (
16642                "service_create_technician_assignment_rows_html".to_owned(),
16643                Value::String(service_create_technician_rows_html),
16644            ),
16645        ]),
16646    )?;
16647    render_fragment_with_params(
16648        app_root,
16649        "templates/businesses/fragments/business_admin_services_manage.html",
16650        serde_json::Map::from_iter([
16651            (
16652                "availability_path".to_owned(),
16653                Value::String(availability_path),
16654            ),
16655            (
16656                "services_body_html".to_owned(),
16657                Value::String(services_body_html),
16658            ),
16659        ]),
16660    )
16661}
16662
16663/// Performs dynamic business detail admin page params from root JSON.
16664///
16665/// # Parameters
16666///
16667/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json`].
16668/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json`].
16669/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json`].
16670///
16671/// # Returns
16672///
16673/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json`] can produce a value and [`None`] otherwise.
16674///
16675/// # Performance
16676///
16677/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json`].
16678///
16679/// # Examples
16680///
16681/// ```rust,ignore
16682/// let _result = pharos_native::runtime::json_commands::dynamic_business_detail_admin_page_params_from_root_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
16683/// ```
16684///
16685/// # Related
16686///
16687/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
16688pub fn dynamic_business_detail_admin_page_params_from_root_json(
16689    root: &Value,
16690    business_slug: &str,
16691    app_root: &Path,
16692) -> Option<String> {
16693    if std::env::var("PHAROS_TRACE_ADMIN_RENDER").ok().as_deref() == Some("1") {
16694        eprintln!("TRACE admin render start slug={business_slug}");
16695    }
16696    let business = bounded_state_array(root, "businesses")
16697        .iter()
16698        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
16699    let business_id = business.get("id").and_then(Value::as_i64)?;
16700    let business_name = business.get("name").map(value_to_text).unwrap_or_default();
16701    let landing_path = format!("/b/{business_slug}/");
16702    let calendar_path = format!("/business/{business_slug}/calendar/");
16703    let edit_path = format!("/businesses/{business_slug}/edit/");
16704    let toggle_path = format!("/businesses/{business_slug}/toggle-public/");
16705    let delete_path = format!("/businesses/{business_slug}/delete/");
16706    let invite_create_path = format!("/businesses/{business_slug}/invites/new/");
16707    let service_create_path = format!("/businesses/{business_slug}/services/new/");
16708    let technician_create_path = format!("/businesses/{business_slug}/technicians/new/");
16709    let availability_create_path = format!("/businesses/{business_slug}/availability/new/");
16710    let is_public = business
16711        .get("is_public")
16712        .and_then(Value::as_bool)
16713        .unwrap_or(false);
16714    let summary = root.get("business_summary")?;
16715    let appointment_count = summary.get("appointment_count")?.as_u64()?;
16716    let technician_count = summary.get("technician_count")?.as_u64()?;
16717    let unassigned_count = summary.get("unassigned_count")?.as_u64()?;
16718    let (payment_provider_id, payment_provider_label) =
16719        business_payment_provider_ui_config(app_root);
16720    let (payment_provider_status_label, payment_provider_status_detail) =
16721        business_payment_provider_status(
16722            root,
16723            business_id,
16724            &payment_provider_id,
16725            &payment_provider_label,
16726        );
16727    let (
16728        payment_provider_connect_path,
16729        payment_provider_refresh_path,
16730        payment_provider_disconnect_path,
16731    ) = business_payment_provider_paths(business_slug, &payment_provider_id);
16732    let connection_status =
16733        if state_find_google_calendar_connection_for_business_logic_local(root, business_id)
16734            .is_some()
16735        {
16736            "Connected"
16737        } else {
16738            "Disconnected"
16739        };
16740    let public_toggle_button =
16741        dynamic_render_business_admin_public_state_button_html(app_root, business_slug, is_public)?;
16742    if std::env::var("PHAROS_TRACE_ADMIN_RENDER").ok().as_deref() == Some("1") {
16743        eprintln!("TRACE admin render public_toggle_button ok");
16744    }
16745    let delete_open_button = render_icon_button_fragment(
16746        app_root,
16747        "business_admin_delete_dialog_open_button",
16748        "button",
16749        "btn btn-danger btn-icon btn-icon-lg",
16750        " title=\"Delete Business\" aria-label=\"Delete Business\" data-dialog-open=\"business-delete-dialog\"",
16751        "templates/shared/fragments/ui_content_delete_business.html",
16752        serde_json::Map::new(),
16753    )?;
16754    let toolbar_html = render_fragment_with_params(
16755        app_root,
16756        "templates/businesses/fragments/business_admin_summary_toolbar.html",
16757        serde_json::Map::from_iter([
16758            (
16759                "landing_path".to_owned(),
16760                Value::String(landing_path.clone()),
16761            ),
16762            (
16763                "calendar_path".to_owned(),
16764                Value::String(calendar_path.clone()),
16765            ),
16766            ("edit_path".to_owned(), Value::String(edit_path.clone())),
16767            ("toggle_path".to_owned(), Value::String(toggle_path.clone())),
16768            (
16769                "business_public_state_toggle_button_ui_html".to_owned(),
16770                Value::String(public_toggle_button),
16771            ),
16772            (
16773                "business_admin_delete_dialog_open_button_ui_html".to_owned(),
16774                Value::String(delete_open_button),
16775            ),
16776        ]),
16777    )?;
16778    if std::env::var("PHAROS_TRACE_ADMIN_RENDER").ok().as_deref() == Some("1") {
16779        eprintln!("TRACE admin render toolbar ok");
16780    }
16781    let mut summary_body_params = serde_json::Map::from_iter([
16782        (
16783            "public_url_path".to_owned(),
16784            Value::String(landing_path.clone()),
16785        ),
16786        (
16787            "payment_provider_status_label".to_owned(),
16788            Value::String(payment_provider_status_label),
16789        ),
16790        (
16791            "payment_provider_status_detail".to_owned(),
16792            Value::String(payment_provider_status_detail),
16793        ),
16794        (
16795            "connection_status".to_owned(),
16796            Value::String(connection_status.to_owned()),
16797        ),
16798        (
16799            "appointment_count".to_owned(),
16800            Value::String(appointment_count.to_string()),
16801        ),
16802        (
16803            "unassigned_count".to_owned(),
16804            Value::String(unassigned_count.to_string()),
16805        ),
16806        (
16807            "technician_count".to_owned(),
16808            Value::String(technician_count.to_string()),
16809        ),
16810        (
16811            "payment_provider_setup_path".to_owned(),
16812            Value::String(format!("/businesses/{business_slug}/connect-stripe/")),
16813        ),
16814        (
16815            "payment_provider_connect_path".to_owned(),
16816            Value::String(payment_provider_connect_path),
16817        ),
16818        (
16819            "payment_provider_refresh_path".to_owned(),
16820            Value::String(payment_provider_refresh_path),
16821        ),
16822        (
16823            "payment_provider_disconnect_path".to_owned(),
16824            Value::String(payment_provider_disconnect_path),
16825        ),
16826        (
16827            "business_admin_refresh_payment_provider_button_ui_html".to_owned(),
16828            Value::String(payment_provider_action_button_html(
16829                app_root,
16830                "business_admin_refresh_payment_provider_button",
16831                "Refresh status",
16832                "btn btn-secondary",
16833            )?),
16834        ),
16835        (
16836            "business_admin_disconnect_payment_provider_button_ui_html".to_owned(),
16837            Value::String(payment_provider_action_button_html(
16838                app_root,
16839                "business_admin_disconnect_payment_provider_button",
16840                "Disconnect",
16841                "btn btn-danger",
16842            )?),
16843        ),
16844        (
16845            "business_admin_google_mode_input_ui_html".to_owned(),
16846            Value::String(render_hidden_input_fragment(
16847                app_root,
16848                "business_admin_google_mode_input",
16849                "mode",
16850                "business",
16851            )?),
16852        ),
16853        (
16854            "business_admin_google_slug_input_ui_html".to_owned(),
16855            Value::String(render_hidden_input_fragment(
16856                app_root,
16857                "business_admin_google_slug_input",
16858                "business_slug",
16859                business_slug,
16860            )?),
16861        ),
16862        (
16863            "business_admin_google_next_input_ui_html".to_owned(),
16864            Value::String(render_hidden_input_fragment(
16865                app_root,
16866                "business_admin_google_next_input",
16867                "next",
16868                &format!("/businesses/{business_slug}/"),
16869            )?),
16870        ),
16871        (
16872            "business_admin_connect_google_button_ui_html".to_owned(),
16873            Value::String(render_fragment_with_params(
16874                app_root,
16875                "templates/shared/fragments/ui_button.html",
16876                Map::from_iter([
16877                    (
16878                        "id".to_owned(),
16879                        Value::String("business_admin_connect_google_button".to_owned()),
16880                    ),
16881                    ("button_type".to_owned(), Value::String("submit".to_owned())),
16882                    (
16883                        "class_name".to_owned(),
16884                        Value::String("btn btn-primary".to_owned()),
16885                    ),
16886                    ("attributes_html".to_owned(), Value::String(String::new())),
16887                    (
16888                        "content_html".to_owned(),
16889                        Value::String("Connect Google Calendar".to_owned()),
16890                    ),
16891                ]),
16892            )?),
16893        ),
16894    ]);
16895    for (key, value) in super::payment_provider::payment_provider_template_params(
16896        root,
16897        app_root,
16898        business_slug,
16899        &payment_provider_id,
16900    ) {
16901        summary_body_params.insert(key, value);
16902    }
16903    for key in [
16904        "owner_payment_provider_status_label",
16905        "owner_payment_provider_status_icon",
16906        "owner_payment_provider_mode_demo_label",
16907        "owner_payment_provider_mode_live_label",
16908        "owner_payment_provider_credentials_state_label",
16909        "owner_payment_provider_setup_eyebrow",
16910        "owner_payment_provider_credentials_headline",
16911        "owner_payment_provider_credentials_body",
16912        "owner_payment_provider_client_id_label",
16913        "owner_payment_provider_client_id_placeholder",
16914        "owner_payment_provider_client_secret_label",
16915        "owner_payment_provider_client_secret_placeholder",
16916        "owner_payment_provider_save_credentials_label",
16917        "owner_payment_provider_delete_credentials_label",
16918        "owner_payment_provider_connect_label",
16919        "owner_payment_provider_refresh_label",
16920    ] {
16921        if let Some(value) = super::payment_provider::payment_provider_copy_value(app_root, key) {
16922            summary_body_params.insert(key.to_owned(), Value::String(value));
16923        }
16924    }
16925    summary_body_params.insert(
16926        "owner_payment_provider_action_href".to_owned(),
16927        Value::String(format!(
16928            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/test/"
16929        )),
16930    );
16931    summary_body_params.insert(
16932        "owner_payment_provider_refresh_href".to_owned(),
16933        Value::String(format!(
16934            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/refresh/"
16935        )),
16936    );
16937    summary_body_params.insert(
16938        "owner_payment_provider_credentials_href".to_owned(),
16939        Value::String(format!(
16940            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/"
16941        )),
16942    );
16943    summary_body_params.insert(
16944        "owner_payment_provider_credentials_delete_href".to_owned(),
16945        Value::String(format!(
16946            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/delete/"
16947        )),
16948    );
16949    summary_body_params.insert(
16950        "owner_payment_provider_mode_href".to_owned(),
16951        Value::String(format!(
16952            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/mode/"
16953        )),
16954    );
16955    summary_body_params.insert(
16956        "payment_provider_feedback_message".to_owned(),
16957        Value::String(String::new()),
16958    );
16959    let summary_body_html = render_fragment_with_params(
16960        app_root,
16961        "templates/businesses/fragments/business_admin_summary_body.html",
16962        summary_body_params,
16963    )?;
16964    if std::env::var("PHAROS_TRACE_ADMIN_RENDER").ok().as_deref() == Some("1") {
16965        eprintln!("TRACE admin render summary_body ok");
16966    }
16967    let invite_body_html = render_fragment_with_params(
16968        app_root,
16969        "templates/businesses/fragments/business_admin_invite_body.html",
16970        serde_json::Map::from_iter([
16971            (
16972                "invite_create_path".to_owned(),
16973                Value::String(invite_create_path.clone()),
16974            ),
16975            (
16976                "business_admin_invite_email_input_ui_html".to_owned(),
16977                Value::String(render_compact_input_fragment(
16978                    app_root,
16979                    "business_admin_invite_email_input",
16980                    "email",
16981                    "email",
16982                    "Email",
16983                    "",
16984                    "form-control form-control-compact",
16985                    " placeholder=\"Email\" autocomplete=\"email\" aria-label=\"Email\" required",
16986                )?),
16987            ),
16988            (
16989                "business_admin_invite_account_type_select_ui_html".to_owned(),
16990                Value::String(render_compact_select_fragment(
16991                    app_root,
16992                    "business_admin_invite_account_type_select",
16993                    "account_type",
16994                    "Account type",
16995                    "form-control form-control-compact",
16996                    " aria-label=\"Account type\"",
16997                    [
16998                        ("business_customer", "Customer", true),
16999                        ("business_manager", "Manager", false),
17000                        ("business_technician", "Technician", false),
17001                    ]
17002                    .into_iter()
17003                    .map(|(value, label, selected)| {
17004                        render_fragment_with_params(
17005                            app_root,
17006                            "templates/shared/fragments/select_option.html",
17007                            Map::from_iter([
17008                                ("option_value".to_owned(), Value::String(value.to_owned())),
17009                                ("option_label".to_owned(), Value::String(label.to_owned())),
17010                                (
17011                                    "selected_attr".to_owned(),
17012                                    Value::String(
17013                                        if selected { " selected" } else { "" }.to_owned(),
17014                                    ),
17015                                ),
17016                            ]),
17017                        )
17018                    })
17019                    .collect::<Option<Vec<_>>>()?
17020                    .join(""),
17021                )?),
17022            ),
17023            (
17024                "business_admin_invite_submit_button_ui_html".to_owned(),
17025                Value::String(render_icon_button_fragment(
17026                    app_root,
17027                    "business_admin_invite_submit_button",
17028                    "submit",
17029                    "btn btn-success btn-icon btn-icon-sm business-admin-save-button",
17030                    " title=\"Send\" aria-label=\"Send\"",
17031                    "templates/shared/fragments/ui_content_create_invite.html",
17032                    serde_json::Map::new(),
17033                )?),
17034            ),
17035        ]),
17036    )?;
17037    let top_grid_html = render_fragment_with_params(
17038        app_root,
17039        "templates/businesses/fragments/business_admin_top_grid.html",
17040        Map::from_iter([
17041            (
17042                "business_name".to_owned(),
17043                Value::String(business_name.clone()),
17044            ),
17045            ("toolbar_html".to_owned(), Value::String(toolbar_html)),
17046            (
17047                "summary_body_html".to_owned(),
17048                Value::String(summary_body_html),
17049            ),
17050            (
17051                "invite_body_html".to_owned(),
17052                Value::String(invite_body_html),
17053            ),
17054        ]),
17055    )?;
17056    let service_rows_html =
17057        dynamic_business_admin_service_cards_html(root, business_slug, app_root)?;
17058    let service_create_technician_rows_html =
17059        technician_checkboxes_html(app_root, root, business_id, 0, "No technicians yet.", true)
17060            .or_else(|| {
17061                render_fragment_with_params(
17062                    app_root,
17063                    "templates/shared/fragments/muted_text.html",
17064                    Map::from_iter([(
17065                        "message".to_owned(),
17066                        Value::String("No technicians yet.".to_owned()),
17067                    )]),
17068                )
17069            })?;
17070    let services_panel_html = render_workspace_panel_html_business_logic_local(
17071        app_root,
17072        "card business-admin-services-card",
17073        "business-admin-services-header",
17074        "Services",
17075        "",
17076        &render_fragment_with_params(
17077            app_root,
17078            "templates/businesses/fragments/business_admin_services_body.html",
17079            serde_json::Map::from_iter([
17080                (
17081                    "service_rows_html".to_owned(),
17082                    Value::String(service_rows_html),
17083                ),
17084                (
17085                    "service_create_path".to_owned(),
17086                    Value::String(service_create_path),
17087                ),
17088                (
17089                    "business_admin_service_name_input_ui_html".to_owned(),
17090                    Value::String(render_compact_input_fragment(
17091                        app_root,
17092                        "business_admin_service_name_input",
17093                        "text",
17094                        "name",
17095                        "Name",
17096                        "",
17097                        "form-control form-control-compact",
17098                        " placeholder=\"Name\" autocomplete=\"false\" aria-label=\"Name\" required",
17099                    )?),
17100                ),
17101                (
17102                    "business_admin_service_cost_input_ui_html".to_owned(),
17103                    Value::String(render_compact_input_fragment(
17104                        app_root,
17105                        "business_admin_service_cost_input",
17106                        "text",
17107                        "cost",
17108                        "Cost",
17109                        "",
17110                        "form-control form-control-compact",
17111                        " placeholder=\"Cost\" autocomplete=\"false\" aria-label=\"Cost\" inputmode=\"decimal\" required",
17112                    )?),
17113                ),
17114                (
17115                    "business_admin_service_duration_input_ui_html".to_owned(),
17116                    Value::String(render_compact_input_fragment(
17117                        app_root,
17118                        "business_admin_service_duration_input",
17119                        "number",
17120                        "duration_minutes",
17121                        "Duration",
17122                        "45",
17123                        "form-control form-control-compact",
17124                        " min=\"1\" max=\"999\" placeholder=\"Time\" autocomplete=\"false\" aria-label=\"Duration\" required",
17125                    )?),
17126                ),
17127                (
17128                    "business_admin_service_sort_order_select_ui_html".to_owned(),
17129                    Value::String(render_compact_select_fragment(
17130                        app_root,
17131                        "service-create-sort-order",
17132                        "sort_order",
17133                        "Display Order",
17134                        "form-control form-control-compact",
17135                        " aria-label=\"Display Order\" required",
17136                        service_sort_order_options_html(app_root, root, business_id, 0, true)?,
17137                    )?),
17138                ),
17139                (
17140                    "business_admin_service_description_textarea_ui_html".to_owned(),
17141                    Value::String(render_textarea_fragment(
17142                        app_root,
17143                        &format!("service-create-description-{business_slug}"),
17144                        "description",
17145                        "Description",
17146                        "",
17147                        "form-control",
17148                        " rows=\"4\" aria-label=\"Description\"",
17149                    )?),
17150                ),
17151                (
17152                    "business_admin_service_image_input_ui_html".to_owned(),
17153                    Value::String(render_fragment_with_params(
17154                        app_root,
17155                        "templates/shared/fragments/ui_input.html",
17156                        serde_json::Map::from_iter([
17157                            (
17158                                "id".to_owned(),
17159                                Value::String("service-create-image".to_owned()),
17160                            ),
17161                            ("input_type".to_owned(), Value::String("file".to_owned())),
17162                            (
17163                                "name".to_owned(),
17164                                Value::String("service_image".to_owned()),
17165                            ),
17166                            (
17167                                "label".to_owned(),
17168                                Value::String("Service image".to_owned()),
17169                            ),
17170                            (
17171                                "label_class".to_owned(),
17172                                Value::String("sr-only".to_owned()),
17173                            ),
17174                            (
17175                                "class_name".to_owned(),
17176                                Value::String("sr-only business-edit-hidden-input".to_owned()),
17177                            ),
17178                            ("value".to_owned(), Value::String(String::new())),
17179                            (
17180                                "attributes_html".to_owned(),
17181                                Value::String(" accept=\"image/*\" data-file-input-label=\"service-create-image-file-name\"".to_owned()),
17182                            ),
17183                            ("help_html".to_owned(), Value::String(String::new())),
17184                        ]),
17185                    )?),
17186                ),
17187                (
17188                    "business_admin_service_submit_button_ui_html".to_owned(),
17189                    Value::String(render_icon_button_fragment(
17190                        app_root,
17191                        "business_admin_service_submit_button",
17192                        "submit",
17193                        "btn btn-success btn-icon btn-icon-sm business-admin-save-button",
17194                        " title=\"Save Service\" aria-label=\"Save Service\"",
17195                        "templates/shared/fragments/ui_content_save_service.html",
17196                        serde_json::Map::new(),
17197                    )?),
17198                ),
17199                (
17200                    "service_create_technicians_empty_style".to_owned(),
17201                    Value::String("display:none;".to_owned()),
17202                ),
17203                (
17204                    "service_create_technicians_empty_message".to_owned(),
17205                    Value::String("No technicians yet.".to_owned()),
17206                ),
17207                (
17208                    "service_create_technician_assignment_rows_html".to_owned(),
17209                    Value::String(service_create_technician_rows_html),
17210                ),
17211            ]),
17212        )?,
17213    )?;
17214    let availability_rows_html =
17215        dynamic_render_business_admin_availability_rows_html(root, business_slug, app_root)?;
17216    let availability_body_html = render_fragment_with_params(
17217        app_root,
17218        "templates/businesses/fragments/business_admin_availability_body.html",
17219        serde_json::Map::from_iter([
17220            (
17221                "availability_rows_html".to_owned(),
17222                Value::String(availability_rows_html),
17223            ),
17224            (
17225                "availability_create_path".to_owned(),
17226                Value::String(availability_create_path.clone()),
17227            ),
17228            (
17229                "business_admin_availability_day_select_ui_html".to_owned(),
17230                Value::String(render_compact_select_fragment(
17231                    app_root,
17232                    &format!("availability-day-{business_slug}"),
17233                    "day_of_week",
17234                    "Day",
17235                    "form-control form-control-compact availability-inline-input",
17236                    " autocomplete=\"off\"",
17237                    render_day_select_options(app_root, "Mon", true)?,
17238                )?),
17239            ),
17240            (
17241                "business_admin_availability_start_time_input_ui_html".to_owned(),
17242                Value::String(render_compact_input_fragment(
17243                    app_root,
17244                    &format!("availability-create-start-{business_slug}"),
17245                    "time",
17246                    "start_time",
17247                    "Start",
17248                    "09:00",
17249                    "form-control form-control-compact availability-inline-input",
17250                    " autocomplete=\"off\"",
17251                )?),
17252            ),
17253            (
17254                "business_admin_availability_end_time_input_ui_html".to_owned(),
17255                Value::String(render_compact_input_fragment(
17256                    app_root,
17257                    &format!("availability-create-end-{business_slug}"),
17258                    "time",
17259                    "end_time",
17260                    "End",
17261                    "17:00",
17262                    "form-control form-control-compact availability-inline-input",
17263                    " autocomplete=\"off\"",
17264                )?),
17265            ),
17266            (
17267                "business_admin_availability_submit_button_ui_html".to_owned(),
17268                Value::String(render_icon_button_fragment(
17269                    app_root,
17270                    &format!("availability-submit-{business_slug}"),
17271                    "submit",
17272                    "btn btn-success btn-icon btn-icon-lg business-admin-save-button",
17273                    "",
17274                    "templates/shared/fragments/ui_content_apply_hours.html",
17275                    serde_json::Map::new(),
17276                )?),
17277            ),
17278        ]),
17279    )?;
17280    let availability_panel_html = render_workspace_panel_html_business_logic_local(
17281        app_root,
17282        "card business-admin-half-card business-admin-availability-card",
17283        "business-admin-services-header",
17284        "Availability",
17285        "",
17286        &availability_body_html,
17287    )?;
17288    let technician_body_html = render_fragment_with_params(
17289        app_root,
17290        "templates/businesses/fragments/business_admin_technicians_body.html",
17291        serde_json::Map::from_iter([
17292            (
17293                "technician_rows_html".to_owned(),
17294                Value::String(
17295                    super::business::dynamic_business_admin_technician_rows_html_from_root(
17296                        root,
17297                        business_slug,
17298                        app_root,
17299                    )?,
17300                ),
17301            ),
17302            (
17303                "technician_create_path".to_owned(),
17304                Value::String(technician_create_path),
17305            ),
17306            (
17307                "business_admin_technician_name_input_ui_html".to_owned(),
17308                Value::String(render_compact_input_fragment(
17309                    app_root,
17310                    "business_admin_technician_name_input",
17311                    "text",
17312                    "name",
17313                    "Name",
17314                    "",
17315                    "form-control form-control-compact",
17316                    " placeholder=\"Name\" autocomplete=\"name\" aria-label=\"Name\" required",
17317                )?),
17318            ),
17319            (
17320                "business_admin_technician_email_input_ui_html".to_owned(),
17321                Value::String(render_compact_input_fragment(
17322                    app_root,
17323                    "business_admin_technician_email_input",
17324                    "email",
17325                    "email",
17326                    "Email",
17327                    "",
17328                    "form-control form-control-compact",
17329                    " placeholder=\"Email\" autocomplete=\"email\" aria-label=\"Email\" required",
17330                )?),
17331            ),
17332            (
17333                "business_admin_technician_submit_button_ui_html".to_owned(),
17334                Value::String(render_icon_button_fragment(
17335                    app_root,
17336                    "business_admin_technician_submit_button",
17337                    "button",
17338                    "btn btn-success btn-icon btn-icon-sm business-admin-save-button business-admin-technician-add-button",
17339                    &format!(
17340                        " title=\"Add Technician\" aria-label=\"Add Technician\" hx-post=\"/businesses/{business_slug}/technicians/new/\" hx-include=\"closest form\" hx-target=\"#business-technician-rows\" hx-swap=\"innerHTML\""
17341                    ),
17342                    "templates/shared/fragments/ui_content_add_technician.html",
17343                    serde_json::Map::new(),
17344                )?),
17345            ),
17346        ]),
17347    )?;
17348    let technician_panel_html = render_workspace_panel_html_business_logic_local(
17349        app_root,
17350        "card business-admin-half-card business-admin-sticky-card",
17351        "business-admin-services-header",
17352        "Technicians",
17353        "",
17354        &technician_body_html,
17355    )?;
17356    let lower_grid_html = render_workspace_split_grid_html_business_logic_local(
17357        app_root,
17358        "business-admin-half-grid",
17359        &availability_panel_html,
17360        &technician_panel_html,
17361    )?;
17362    let delete_dialog_html = render_workspace_dialog_html_business_logic_local(
17363        app_root,
17364        "business-delete-dialog",
17365        "business-delete-dialog",
17366        "business-delete-dialog-shell",
17367        "business-delete-dialog-copy",
17368        &render_fragment_with_params(
17369            app_root,
17370            "templates/businesses/fragments/business_admin_delete_dialog_copy.html",
17371            serde_json::Map::from_iter([(
17372                "business_name".to_owned(),
17373                Value::String(business_name.clone()),
17374            )]),
17375        )?,
17376        "business-delete-dialog-actions",
17377        &render_fragment_with_params(
17378            app_root,
17379            "templates/businesses/fragments/business_admin_delete_dialog_actions.html",
17380            serde_json::Map::from_iter([
17381                ("delete_path".to_owned(), Value::String(delete_path)),
17382                (
17383                    "business_admin_delete_confirm_button_ui_html".to_owned(),
17384                    Value::String(render_icon_button_fragment(
17385                        app_root,
17386                        "business_admin_delete_confirm_button",
17387                        "submit",
17388                        "btn btn-danger btn-icon btn-icon-lg",
17389                        " title=\"Delete Business\" aria-label=\"Delete Business\"",
17390                        "templates/shared/fragments/ui_content_delete_business.html",
17391                        serde_json::Map::new(),
17392                    )?),
17393                ),
17394                (
17395                    "business_admin_delete_cancel_button_ui_html".to_owned(),
17396                    Value::String(render_icon_button_fragment(
17397                        app_root,
17398                        "business_admin_delete_cancel_button",
17399                        "button",
17400                        "btn btn-secondary btn-icon btn-icon-lg",
17401                        " title=\"Cancel\" aria-label=\"Cancel\" data-dialog-close=\"true\"",
17402                        "templates/shared/fragments/ui_content_cancel.html",
17403                        serde_json::Map::new(),
17404                    )?),
17405                ),
17406            ]),
17407        )?,
17408    )?;
17409    compact(&Value::Object(serde_json::Map::from_iter([
17410        ("business_name".to_owned(), Value::String(business_name)),
17411        ("top_grid_html".to_owned(), Value::String(top_grid_html)),
17412        (
17413            "services_panel_html".to_owned(),
17414            Value::String(services_panel_html),
17415        ),
17416        ("lower_grid_html".to_owned(), Value::String(lower_grid_html)),
17417        (
17418            "delete_dialog_html".to_owned(),
17419            Value::String(delete_dialog_html),
17420        ),
17421    ])))
17422}
17423
17424/// Builds business calendar page params from a loaded state root.
17425///
17426/// # Parameters
17427///
17428/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17429/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17430/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17431/// - `year`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17432/// - `month`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17433/// - `date`: Input consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17434///
17435/// # Returns
17436///
17437/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`] can produce a value and [`None`] otherwise.
17438///
17439/// # Performance
17440///
17441/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json`].
17442///
17443/// # Examples
17444///
17445/// ```rust,ignore
17446/// let _result = pharos_native::runtime::json_commands::dynamic_business_calendar_template_params_from_root_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
17447/// ```
17448///
17449/// # Related
17450///
17451/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
17452pub fn dynamic_business_calendar_template_params_from_root_json(
17453    root: &Value,
17454    business_slug: &str,
17455    app_root: &Path,
17456    year: Option<&str>,
17457    month: Option<&str>,
17458    date: Option<&str>,
17459    _actor_user_id: i64,
17460    csrf_token: &str,
17461) -> Option<String> {
17462    if std::env::var("PHAROS_TRACE_CALENDAR_RENDER")
17463        .ok()
17464        .as_deref()
17465        == Some("1")
17466    {
17467        eprintln!(
17468            "TRACE calendar render start slug={business_slug} year={:?} month={:?} date={:?}",
17469            year, month, date
17470        );
17471    }
17472    let business = bounded_state_array(root, "businesses")
17473        .iter()
17474        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
17475    let business_id = business.get("id").and_then(Value::as_i64)?;
17476    let business_name = business.get("name").map(value_to_text).unwrap_or_default();
17477    let availability = bounded_state_array(root, "business_availability");
17478    let appointments = bounded_state_array(root, "appointments");
17479    let requested_date = date
17480        .filter(|value| value.len() == 10 && value.as_bytes().get(4) == Some(&b'-'))
17481        .map(ToOwned::to_owned);
17482    let selected_year = year
17483        .and_then(|value| value.parse::<i32>().ok())
17484        .filter(|value| (2000..=2100).contains(value))
17485        .or_else(|| {
17486            requested_date
17487                .as_deref()
17488                .and_then(|value| value.get(0..4))
17489                .and_then(|value| value.parse().ok())
17490        });
17491    let selected_month = month
17492        .and_then(|value| value.parse::<u32>().ok())
17493        .filter(|value| (1..=12).contains(value))
17494        .or_else(|| {
17495            requested_date
17496                .as_deref()
17497                .and_then(|value| value.get(5..7))
17498                .and_then(|value| value.parse().ok())
17499        });
17500    let now = pharos_runtime_core::time::current_timestamp_utc();
17501    let today = now.get(..10)?.to_owned();
17502    let current_year = today.get(..4)?.parse::<i32>().ok()?;
17503    let current_month = today.get(5..7)?.parse::<u32>().ok()?;
17504    let fallback_date = if selected_year.is_none() && selected_month.is_none() {
17505        today
17506    } else {
17507        format!(
17508            "{:04}-{:02}-01",
17509            selected_year.unwrap_or(current_year),
17510            selected_month.unwrap_or(current_month)
17511        )
17512    };
17513    let selected_date = requested_date.unwrap_or(fallback_date);
17514    let selected_year = selected_year
17515        .or_else(|| selected_date.get(0..4).and_then(|value| value.parse().ok()))
17516        .unwrap_or(current_year);
17517    let selected_month = selected_month
17518        .or_else(|| selected_date.get(5..7).and_then(|value| value.parse().ok()))
17519        .unwrap_or(current_month);
17520    let month_label = [
17521        "January",
17522        "February",
17523        "March",
17524        "April",
17525        "May",
17526        "June",
17527        "July",
17528        "August",
17529        "September",
17530        "October",
17531        "November",
17532        "December",
17533    ][selected_month.saturating_sub(1) as usize]
17534        .to_owned();
17535    let days_in_month = days_in_month_business_logic_local(selected_year, selected_month);
17536    let first_day = day_abbrev_for_ymd_business_logic_local(selected_year, selected_month, 1)?;
17537    let first_index = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
17538        .iter()
17539        .position(|day| *day == first_day)
17540        .unwrap_or(0);
17541    let calendar_base_path = format!("/business/{business_slug}/calendar/");
17542    let mut calendar_rows_html = String::new();
17543    for week in 0..6 {
17544        let mut cells_html = String::new();
17545        for column in 0..7 {
17546            let grid_index = week * 7 + column;
17547            let day_number = grid_index - first_index as i32 + 1;
17548            if day_number < 1 || day_number > days_in_month as i32 {
17549                cells_html.push_str(&render_fragment_with_params(
17550                    app_root,
17551                    "templates/businesses/fragments/business_calendar_empty_day_cell.html",
17552                    serde_json::Map::from_iter([(
17553                        "cell_class".to_owned(),
17554                        Value::String("day".to_owned()),
17555                    )]),
17556                )?);
17557                continue;
17558            }
17559            let day_number = day_number as u32;
17560            let date_value = format!("{selected_year:04}-{selected_month:02}-{day_number:02}");
17561            let weekday =
17562                day_abbrev_for_ymd_business_logic_local(selected_year, selected_month, day_number)?;
17563            let day_schedule: Vec<&Value> = availability
17564                .iter()
17565                .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
17566                .filter(|row| {
17567                    business_day_matches_group(
17568                        row.get("day_of_week").and_then(Value::as_str).unwrap_or(""),
17569                        weekday,
17570                    )
17571                })
17572                .collect();
17573            let day_has_booking = appointments.iter().any(|row| {
17574                row_i64_value(row, "business_id") == Some(business_id)
17575                    && row_date_time(row).0 == date_value
17576            });
17577
17578            cells_html.push_str(&render_fragment_with_params(
17579                app_root,
17580                "templates/businesses/fragments/business_calendar_day_cell.html",
17581                serde_json::Map::from_iter([
17582                    (
17583                        "day_cell_classes".to_owned(),
17584                        Value::String(
17585                            [
17586                                (date_value == selected_date).then_some("today"),
17587                                day_has_booking.then_some("has-appointments"),
17588                            ]
17589                            .into_iter()
17590                            .flatten()
17591                            .map(|class_name| format!(" {class_name}"))
17592                            .collect::<String>(),
17593                        ),
17594                    ),
17595                    (
17596                        "day_path".to_owned(),
17597                        Value::String(format!(
17598                            "{calendar_base_path}?year={selected_year}&month={selected_month:02}&date={date_value}"
17599                        )),
17600                    ),
17601                    (
17602                        "day_number".to_owned(),
17603                        Value::String(day_number.to_string()),
17604                    ),
17605                    (
17606                        "day_chip_style".to_owned(),
17607                        Value::String(if date_value == selected_date {
17608                            "background:var(--primary);color:#fff;".to_owned()
17609                        } else if day_has_booking {
17610                            "background:#dcfce7;color:#166534;".to_owned()
17611                        } else {
17612                            "background:var(--gray-200);color:var(--gray-700);".to_owned()
17613                        }),
17614                    ),
17615                    ("appointment_summary".to_owned(), Value::String(String::new())),
17616                    (
17617                        "availability_color".to_owned(),
17618                        Value::String(if day_schedule.is_empty() {
17619                            String::new()
17620                        } else {
17621                            "var(--primary)".to_owned()
17622                        }),
17623                    ),
17624                    (
17625                        "availability_summary".to_owned(),
17626                        Value::String(String::new()),
17627                    ),
17628                ]),
17629            )?);
17630        }
17631        calendar_rows_html.push_str(&render_fragment_with_params(
17632            app_root,
17633            "templates/businesses/fragments/business_calendar_week_row.html",
17634            serde_json::Map::from_iter([("cells_html".to_owned(), Value::String(cells_html))]),
17635        )?);
17636    }
17637    let selected_weekday = selected_date
17638        .get(8..10)
17639        .and_then(|day| day.parse::<u32>().ok())
17640        .and_then(|day| {
17641            day_abbrev_for_ymd_business_logic_local(selected_year, selected_month, day)
17642        })?;
17643    let selected_schedule: Vec<&Value> = availability
17644        .iter()
17645        .filter(|row| row.get("business_id").and_then(Value::as_i64) == Some(business_id))
17646        .filter(|row| {
17647            business_day_matches_group(
17648                row.get("day_of_week").and_then(Value::as_str).unwrap_or(""),
17649                selected_weekday,
17650            )
17651        })
17652        .collect();
17653    let mut selected_schedule_rows_html = String::new();
17654    for row in &selected_schedule {
17655        selected_schedule_rows_html.push_str(&render_fragment_with_params(
17656            app_root,
17657            "templates/businesses/fragments/business_calendar_schedule_row.html",
17658            serde_json::Map::from_iter([
17659                (
17660                    "start_time".to_owned(),
17661                    Value::String(
17662                        row.get("start_time")
17663                            .map(value_to_text)
17664                            .map(|value| formatted_clock_time_business_logic_local(&value))
17665                            .unwrap_or_else(|| "9:00 AM".to_owned()),
17666                    ),
17667                ),
17668                (
17669                    "end_time".to_owned(),
17670                    Value::String(
17671                        row.get("end_time")
17672                            .map(value_to_text)
17673                            .map(|value| formatted_clock_time_business_logic_local(&value))
17674                            .unwrap_or_else(|| "5:00 PM".to_owned()),
17675                    ),
17676                ),
17677            ]),
17678        )?);
17679    }
17680    let default_booking_time = selected_schedule
17681        .first()
17682        .and_then(|row| row.get("start_time"))
17683        .map(value_to_text)
17684        .filter(|value| generated_surface_text_is_time(value))
17685        .map(|value| value.get(0..5).unwrap_or("09:00").to_owned())
17686        .unwrap_or_else(|| "09:00".to_owned());
17687    let mut service_options_html = String::new();
17688    let mut service_option_index = 0usize;
17689    for service in bounded_state_array(root, "services")
17690        .iter()
17691        .filter(|service| row_i64_value(service, "business_id") == Some(business_id))
17692    {
17693        let service_id = row_i64_value(service, "id").unwrap_or(0);
17694        if service_id <= 0 {
17695            continue;
17696        }
17697        let service_label = service
17698            .get("name")
17699            .map(value_to_text)
17700            .filter(|value| !value.is_empty())
17701            .unwrap_or_else(|| format!("Service {service_id}"));
17702        let duration_minutes = row_i64_value(service, "duration_minutes")
17703            .unwrap_or(45)
17704            .max(1);
17705        service_options_html.push_str(&render_fragment_with_params(
17706            app_root,
17707            "templates/businesses/fragments/business_calendar_option_with_duration.html",
17708            Map::from_iter([
17709                (
17710                    "option_value".to_owned(),
17711                    Value::String(service_id.to_string()),
17712                ),
17713                (
17714                    "option_label".to_owned(),
17715                    Value::String(format!("{service_label} · {duration_minutes} min")),
17716                ),
17717                (
17718                    "duration_minutes".to_owned(),
17719                    Value::String(duration_minutes.to_string()),
17720                ),
17721                (
17722                    "booking_option_index".to_owned(),
17723                    Value::String(String::new()),
17724                ),
17725                (
17726                    "selected_attr".to_owned(),
17727                    Value::String(if service_option_index == 0 {
17728                        " selected".to_owned()
17729                    } else {
17730                        String::new()
17731                    }),
17732                ),
17733            ]),
17734        )?);
17735        service_option_index = service_option_index.saturating_add(1);
17736        if let Some(booking_options) = service.get("booking_options").and_then(Value::as_array) {
17737            for (booking_option_index, booking_option) in booking_options.iter().enumerate() {
17738                let option_duration_minutes = row_i64_value(booking_option, "duration_minutes")
17739                    .unwrap_or(duration_minutes)
17740                    .max(1);
17741                let option_label = booking_option
17742                    .get("label")
17743                    .map(value_to_text)
17744                    .filter(|value| !value.is_empty())
17745                    .unwrap_or_else(|| format!("{option_duration_minutes} min"));
17746                service_options_html.push_str(&render_fragment_with_params(
17747                    app_root,
17748                    "templates/businesses/fragments/business_calendar_option_with_duration.html",
17749                    Map::from_iter([
17750                        (
17751                            "option_value".to_owned(),
17752                            Value::String(service_id.to_string()),
17753                        ),
17754                        (
17755                            "option_label".to_owned(),
17756                            Value::String(format!(
17757                                "{service_label} · {option_label} · {option_duration_minutes} min"
17758                            )),
17759                        ),
17760                        (
17761                            "duration_minutes".to_owned(),
17762                            Value::String(option_duration_minutes.to_string()),
17763                        ),
17764                        (
17765                            "booking_option_index".to_owned(),
17766                            Value::String(booking_option_index.to_string()),
17767                        ),
17768                        (
17769                            "selected_attr".to_owned(),
17770                            Value::String(if service_option_index == 0 {
17771                                " selected".to_owned()
17772                            } else {
17773                                String::new()
17774                            }),
17775                        ),
17776                    ]),
17777                )?);
17778                service_option_index = service_option_index.saturating_add(1);
17779            }
17780        }
17781    }
17782    let mut internal_technician_options_html = String::new();
17783    for technician in bounded_state_array(root, "technicians")
17784        .iter()
17785        .filter(|technician| row_i64_value(technician, "business_id") == Some(business_id))
17786    {
17787        let technician_id = row_i64_value(technician, "id").unwrap_or(0);
17788        if technician_id <= 0 {
17789            continue;
17790        }
17791        let technician_label = technician
17792            .get("name")
17793            .map(value_to_text)
17794            .filter(|value| !value.is_empty())
17795            .unwrap_or_else(|| format!("Technician {technician_id}"));
17796        let booked_slots = appointments
17797            .iter()
17798            .filter(|appointment| row_i64_value(appointment, "business_id") == Some(business_id))
17799            .filter(|appointment| {
17800                row_i64_value(appointment, "technician_id") == Some(technician_id)
17801            })
17802            .filter(|appointment| row_date_time(appointment).0 == selected_date)
17803            .filter(|appointment| {
17804                appointment.get("status").map(value_to_text).as_deref() != Some("cancelled")
17805            })
17806            .filter_map(|appointment| {
17807                let (_, booked_time) = row_date_time(appointment);
17808                let duration = appointment
17809                    .get("service_duration_minutes")
17810                    .and_then(Value::as_i64)
17811                    .or_else(|| {
17812                        row_i64_value(appointment, "service_id")
17813                            .and_then(|service_id| {
17814                                state_row_by_i64(root, "services", "id", service_id)
17815                            })
17816                            .and_then(|service| row_i64_value(service, "duration_minutes"))
17817                    })
17818                    .unwrap_or(45)
17819                    .max(1);
17820                generated_surface_text_is_time(&booked_time)
17821                    .then(|| format!("{}:{duration}", booked_time.get(0..5).unwrap_or("00:00")))
17822            })
17823            .collect::<Vec<_>>()
17824            .join(",");
17825        internal_technician_options_html.push_str(&render_fragment_with_params(
17826            app_root,
17827            "templates/businesses/fragments/business_calendar_technician_option.html",
17828            Map::from_iter([
17829                (
17830                    "option_value".to_owned(),
17831                    Value::String(technician_id.to_string()),
17832                ),
17833                ("option_label".to_owned(), Value::String(technician_label)),
17834                ("booked_slots".to_owned(), Value::String(booked_slots)),
17835                ("selected_attr".to_owned(), Value::String(String::new())),
17836            ]),
17837        )?);
17838    }
17839    let mut appointment_rows_html = String::new();
17840    for row in appointments
17841        .iter()
17842        .filter(|row| row_i64_value(row, "business_id") == Some(business_id))
17843        .filter(|row| row_date_time(row).0 == selected_date)
17844    {
17845        let appointment_id = row_i64_value(row, "id").unwrap_or(0);
17846        let (appointment_date, appointment_time) = row_date_time(row);
17847        let service = row_i64_value(row, "service_id")
17848            .and_then(|id| state_row_by_i64(root, "services", "id", id));
17849        let appointment_duration_minutes = row
17850            .get("service_duration_minutes")
17851            .and_then(Value::as_i64)
17852            .or_else(|| service.and_then(|service| row_i64_value(service, "duration_minutes")))
17853            .unwrap_or(45)
17854            .max(1);
17855        let appointment_end_time = row
17856            .get("end_time")
17857            .map(value_to_text)
17858            .and_then(|value| {
17859                value
17860                    .get(11..16)
17861                    .or_else(|| value.get(0..5))
17862                    .map(ToOwned::to_owned)
17863            })
17864            .filter(|value| !value.is_empty())
17865            .or_else(|| {
17866                appointment_time_plus_minutes(&appointment_time, appointment_duration_minutes)
17867            })
17868            .unwrap_or_default();
17869        let technician = row_i64_value(row, "technician_id")
17870            .and_then(|id| state_row_by_i64(root, "technicians", "id", id));
17871        let customer =
17872            row_i64_value(row, "user_id").and_then(|id| state_row_by_i64(root, "users", "id", id));
17873        let appointment_type = service
17874            .and_then(|value| value.get("name"))
17875            .map(value_to_text)
17876            .filter(|value| !value.is_empty())
17877            .unwrap_or_else(|| "Appointment".to_owned());
17878        let technician_name = technician
17879            .and_then(|value| value.get("name"))
17880            .map(value_to_text)
17881            .filter(|value| !value.is_empty())
17882            .unwrap_or_else(|| "Unassigned".to_owned());
17883        let customer_name = customer
17884            .and_then(|value| value.get("full_name").or_else(|| value.get("display_name")))
17885            .map(value_to_text)
17886            .filter(|value| !value.is_empty())
17887            .unwrap_or_else(|| "Customer".to_owned());
17888        let customer_email = customer
17889            .and_then(|value| value.get("email"))
17890            .map(value_to_text)
17891            .unwrap_or_default();
17892        let payment_status = row
17893            .get("payment_status")
17894            .map(value_to_text)
17895            .filter(|value| !value.is_empty())
17896            .unwrap_or_else(|| "not required".to_owned());
17897        let notes_text = row
17898            .get("notes")
17899            .map(value_to_text)
17900            .filter(|value| !value.is_empty())
17901            .unwrap_or_else(|| "None".to_owned());
17902        let dialog_id = format!("business-calendar-appointment-{appointment_id}");
17903        let csrf_token_input_ui_html = render_fragment_with_params(
17904            app_root,
17905            "templates/shared/fragments/csrf_hidden_input.html",
17906            Map::from_iter([(
17907                "csrf_token".to_owned(),
17908                Value::String(csrf_token.to_owned()),
17909            )]),
17910        )?;
17911        let mut technician_options_html = String::new();
17912        let current_technician_id = row_i64_value(row, "technician_id").unwrap_or(0);
17913        for option in bounded_state_array(root, "technicians")
17914            .iter()
17915            .filter(|technician| row_i64_value(technician, "business_id") == Some(business_id))
17916        {
17917            let technician_id = row_i64_value(option, "id").unwrap_or(0);
17918            if technician_id <= 0 {
17919                continue;
17920            }
17921            if !super::business::dynamic_technician_unbooked_for_slot(
17922                root,
17923                business_id,
17924                technician_id,
17925                &appointment_date,
17926                &appointment_time,
17927                appointment_duration_minutes,
17928                appointment_id,
17929            ) {
17930                continue;
17931            }
17932            let technician_label = option
17933                .get("name")
17934                .map(value_to_text)
17935                .filter(|value| !value.is_empty())
17936                .unwrap_or_else(|| format!("Technician {technician_id}"));
17937            technician_options_html.push_str(&render_fragment_with_params(
17938                app_root,
17939                "templates/shared/fragments/select_option.html",
17940                Map::from_iter([
17941                    (
17942                        "option_value".to_owned(),
17943                        Value::String(technician_id.to_string()),
17944                    ),
17945                    ("option_label".to_owned(), Value::String(technician_label)),
17946                    (
17947                        "selected_attr".to_owned(),
17948                        Value::String(if technician_id == current_technician_id {
17949                            " selected".to_owned()
17950                        } else {
17951                            String::new()
17952                        }),
17953                    ),
17954                ]),
17955            )?);
17956        }
17957        let return_to_path = format!(
17958            "/business/{business_slug}/calendar/?year={selected_year}&month={selected_month:02}&date={selected_date}"
17959        );
17960        let dialog_copy_html = render_fragment_with_params(
17961            app_root,
17962            "templates/businesses/fragments/business_calendar_appointment_dialog_copy.html",
17963            Map::from_iter([
17964                (
17965                    "appointment_id".to_owned(),
17966                    Value::String(appointment_id.to_string()),
17967                ),
17968                (
17969                    "appointment_type".to_owned(),
17970                    Value::String(appointment_type.clone()),
17971                ),
17972                (
17973                    "appointment_duration_minutes".to_owned(),
17974                    Value::String(appointment_duration_minutes.to_string()),
17975                ),
17976                (
17977                    "appointment_date".to_owned(),
17978                    Value::String(appointment_date.clone()),
17979                ),
17980                (
17981                    "appointment_time".to_owned(),
17982                    Value::String(formatted_clock_time_business_logic_local(&appointment_time)),
17983                ),
17984                (
17985                    "appointment_end_time".to_owned(),
17986                    Value::String(formatted_clock_time_business_logic_local(
17987                        &appointment_end_time,
17988                    )),
17989                ),
17990                (
17991                    "customer_name".to_owned(),
17992                    Value::String(customer_name.clone()),
17993                ),
17994                ("customer_email".to_owned(), Value::String(customer_email)),
17995                (
17996                    "technician_name".to_owned(),
17997                    Value::String(technician_name.clone()),
17998                ),
17999                ("payment_status".to_owned(), Value::String(payment_status)),
18000                ("notes_text".to_owned(), Value::String(notes_text)),
18001            ]),
18002        )?;
18003        let dialog_actions_html = render_fragment_with_params(
18004            app_root,
18005            "templates/businesses/fragments/business_calendar_appointment_dialog_actions.html",
18006            Map::from_iter([
18007                (
18008                    "appointment_id".to_owned(),
18009                    Value::String(appointment_id.to_string()),
18010                ),
18011                (
18012                    "assign_technician_path".to_owned(),
18013                    Value::String(format!("/appointments/{appointment_id}/assign-technician/")),
18014                ),
18015                ("return_to_path".to_owned(), Value::String(return_to_path)),
18016                (
18017                    "technician_options_html".to_owned(),
18018                    Value::String(technician_options_html),
18019                ),
18020                (
18021                    "reschedule_path".to_owned(),
18022                    Value::String(format!("/b/{business_slug}/")),
18023                ),
18024                (
18025                    "complete_path".to_owned(),
18026                    Value::String(format!("/appointments/{appointment_id}/complete/")),
18027                ),
18028                (
18029                    "cancel_path".to_owned(),
18030                    Value::String(format!("/appointments/{appointment_id}/cancel/")),
18031                ),
18032                (
18033                    "csrf_token_input_ui_html".to_owned(),
18034                    Value::String(csrf_token_input_ui_html),
18035                ),
18036            ]),
18037        )?;
18038        let appointment_dialog_html = render_workspace_dialog_html_business_logic_local(
18039            app_root,
18040            &dialog_id,
18041            "business-calendar-dialog",
18042            "business-calendar-dialog-shell",
18043            "business-calendar-dialog-copy",
18044            &dialog_copy_html,
18045            "business-calendar-dialog-actions",
18046            &dialog_actions_html,
18047        )?;
18048        appointment_rows_html.push_str(&render_fragment_with_params(
18049            app_root,
18050            "templates/businesses/fragments/business_calendar_appointment_row.html",
18051            Map::from_iter([
18052                ("dialog_id".to_owned(), Value::String(dialog_id)),
18053                (
18054                    "appointment_type".to_owned(),
18055                    Value::String(appointment_type),
18056                ),
18057                (
18058                    "technician_name".to_owned(),
18059                    Value::String(format!("Assigned: {technician_name}")),
18060                ),
18061                (
18062                    "appointment_time".to_owned(),
18063                    Value::String(formatted_clock_time_business_logic_local(&appointment_time)),
18064                ),
18065                (
18066                    "appointment_dialog_html".to_owned(),
18067                    Value::String(appointment_dialog_html),
18068                ),
18069            ]),
18070        )?);
18071    }
18072    if appointment_rows_html.is_empty() {
18073        appointment_rows_html = render_fragment_with_params(
18074            app_root,
18075            "templates/businesses/fragments/business_calendar_appointments_empty.html",
18076            serde_json::Map::new(),
18077        )?;
18078    }
18079    let return_to_path = format!(
18080        "/business/{business_slug}/calendar/?year={selected_year}&month={selected_month:02}&date={selected_date}"
18081    );
18082    let internal_booking_copy_html = render_fragment_with_params(
18083        app_root,
18084        "templates/businesses/fragments/business_calendar_internal_booking_dialog_copy.html",
18085        Map::from_iter([
18086            (
18087                "business_id".to_owned(),
18088                Value::String(business_id.to_string()),
18089            ),
18090            (
18091                "selected_date".to_owned(),
18092                Value::String(selected_date.clone()),
18093            ),
18094            (
18095                "default_booking_time".to_owned(),
18096                Value::String(default_booking_time),
18097            ),
18098            (
18099                "create_appointment_path".to_owned(),
18100                Value::String(format!(
18101                    "/business/{business_slug}/calendar/appointments/new/"
18102                )),
18103            ),
18104            ("return_to_path".to_owned(), Value::String(return_to_path)),
18105            (
18106                "service_options_html".to_owned(),
18107                Value::String(service_options_html),
18108            ),
18109            (
18110                "internal_technician_options_html".to_owned(),
18111                Value::String(internal_technician_options_html),
18112            ),
18113            (
18114                "csrf_token_input_ui_html".to_owned(),
18115                Value::String(render_fragment_with_params(
18116                    app_root,
18117                    "templates/shared/fragments/csrf_hidden_input.html",
18118                    Map::from_iter([(
18119                        "csrf_token".to_owned(),
18120                        Value::String(csrf_token.to_owned()),
18121                    )]),
18122                )?),
18123            ),
18124        ]),
18125    )?;
18126    let internal_booking_dialog_html = render_workspace_dialog_html_business_logic_local(
18127        app_root,
18128        "business-calendar-internal-booking",
18129        "business-calendar-dialog",
18130        "business-calendar-dialog-shell",
18131        "business-calendar-dialog-copy",
18132        &internal_booking_copy_html,
18133        "business-calendar-dialog-actions",
18134        "",
18135    )?;
18136    let prev_month = if selected_month == 1 {
18137        12
18138    } else {
18139        selected_month - 1
18140    };
18141    let prev_year = if selected_month == 1 {
18142        selected_year - 1
18143    } else {
18144        selected_year
18145    };
18146    let next_month = if selected_month == 12 {
18147        1
18148    } else {
18149        selected_month + 1
18150    };
18151    let next_year = if selected_month == 12 {
18152        selected_year + 1
18153    } else {
18154        selected_year
18155    };
18156    compact(&Value::Object(serde_json::Map::from_iter([
18157        ("business_name".to_owned(), Value::String(business_name)),
18158        (
18159            "landing_path".to_owned(),
18160            Value::String(format!("/b/{business_slug}/")),
18161        ),
18162        (
18163            "manage_path".to_owned(),
18164            Value::String(format!("/businesses/{business_slug}/")),
18165        ),
18166        ("month_label".to_owned(), Value::String(month_label)),
18167        (
18168            "selected_year".to_owned(),
18169            Value::String(selected_year.to_string()),
18170        ),
18171        (
18172            "selected_date".to_owned(),
18173            Value::String(selected_date.clone()),
18174        ),
18175        (
18176            "calendar_rows_html".to_owned(),
18177            Value::String(calendar_rows_html),
18178        ),
18179        (
18180            "selected_schedule_empty_style".to_owned(),
18181            Value::String(if selected_schedule.is_empty() {
18182                String::new()
18183            } else {
18184                "display:none;".to_owned()
18185            }),
18186        ),
18187        (
18188            "selected_schedule_list_style".to_owned(),
18189            Value::String(if selected_schedule.is_empty() {
18190                "display:none;".to_owned()
18191            } else {
18192                "display:flex;".to_owned()
18193            }),
18194        ),
18195        (
18196            "selected_schedule_rows_html".to_owned(),
18197            Value::String(selected_schedule_rows_html),
18198        ),
18199        (
18200            "selected_schedule_cta_style".to_owned(),
18201            Value::String(if selected_schedule.is_empty() {
18202                "display:none".to_owned()
18203            } else {
18204                "display:block;".to_owned()
18205            }),
18206        ),
18207        (
18208            "selected_schedule_public_booking_path".to_owned(),
18209            Value::String(format!("/b/{business_slug}/")),
18210        ),
18211        (
18212            "appointment_rows_html".to_owned(),
18213            Value::String(appointment_rows_html),
18214        ),
18215        (
18216            "internal_booking_dialog_html".to_owned(),
18217            Value::String(internal_booking_dialog_html),
18218        ),
18219        (
18220            "prev_month_path".to_owned(),
18221            Value::String(format!(
18222                "{calendar_base_path}?year={prev_year}&month={prev_month:02}"
18223            )),
18224        ),
18225        (
18226            "next_month_path".to_owned(),
18227            Value::String(format!(
18228                "{calendar_base_path}?year={next_year}&month={next_month:02}"
18229            )),
18230        ),
18231    ])))
18232}
18233
18234/// Builds the business create page parameters.
18235///
18236/// # Parameters
18237///
18238/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_create_page_params_json`].
18239/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_create_page_params_json`].
18240/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_create_page_params_json`].
18241///
18242/// # Returns
18243///
18244/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_create_page_params_json`] can produce a value and [`None`] otherwise.
18245///
18246/// # Examples
18247///
18248/// ```rust,ignore
18249/// let _result = pharos_native::runtime::json_commands::dynamic_business_create_page_params_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
18250/// ```
18251///
18252/// # Related
18253///
18254/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18255pub fn dynamic_business_create_page_params_json(
18256    root: &Value,
18257    business_slug: &str,
18258    app_root: &Path,
18259) -> Option<String> {
18260    dynamic_business_admin_page_params_json(root, business_slug, app_root)
18261}
18262
18263/// Builds the business dashboard page parameters.
18264///
18265/// # Parameters
18266///
18267/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_from_root_json`].
18268/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_from_root_json`].
18269/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_from_root_json`].
18270///
18271/// # Returns
18272///
18273/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_from_root_json`] can produce a value and [`None`] otherwise.
18274///
18275/// # Examples
18276///
18277/// ```rust,ignore
18278/// let _result = pharos_native::runtime::json_commands::dynamic_business_dashboard_page_params_from_root_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
18279/// ```
18280///
18281/// # Related
18282///
18283/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18284pub fn dynamic_business_dashboard_page_params_from_root_json(
18285    root: &Value,
18286    business_slug: &str,
18287    app_root: &Path,
18288) -> Option<String> {
18289    dynamic_business_admin_page_params_json(root, business_slug, app_root)
18290}
18291
18292/// Builds the business dashboard page parameters from state.
18293///
18294/// # Parameters
18295///
18296/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_json`].
18297/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_json`].
18298/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_json`].
18299///
18300/// # Returns
18301///
18302/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_dashboard_page_params_json`] can produce a value and [`None`] otherwise.
18303///
18304/// # Examples
18305///
18306/// ```rust,ignore
18307/// let _result = pharos_native::runtime::json_commands::dynamic_business_dashboard_page_params_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
18308/// ```
18309///
18310/// # Related
18311///
18312/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18313pub fn dynamic_business_dashboard_page_params_json(
18314    root: &Value,
18315    business_slug: &str,
18316    app_root: &Path,
18317) -> Option<String> {
18318    dynamic_business_dashboard_page_params_from_root_json(root, business_slug, app_root)
18319}
18320
18321/// Builds a business edit page parameter document.
18322///
18323/// # Parameters
18324///
18325/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local`].
18326/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local`].
18327/// - `business_id`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local`].
18328/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local`].
18329///
18330/// # Returns
18331///
18332/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local`] can produce a value and [`None`] otherwise.
18333///
18334/// # Examples
18335///
18336/// ```rust,ignore
18337/// let _result = pharos_native::runtime::json_commands::dynamic_business_edit_page_params_from_root_json_dup_local(std::path::Path::new("."), "demo", todo!(), std::path::Path::new("apps/dev_docs"));
18338/// ```
18339///
18340/// # Related
18341///
18342/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18343pub fn dynamic_business_edit_page_params_from_root_json_dup_local(
18344    root: &Value,
18345    business_slug: &str,
18346    business_id: i64,
18347    app_root: &Path,
18348) -> Option<String> {
18349    let mut extra = Map::new();
18350    extra.insert("business_slug".into(), Value::String(business_slug.into()));
18351    extra.insert("business_id".into(), Value::from(business_id));
18352    extra.insert(
18353        "app_root".into(),
18354        Value::String(app_root.to_string_lossy().into_owned()),
18355    );
18356    page_params_value(root, "business-edit", extra)
18357}
18358
18359/// Builds the business edit page parameters from state.
18360///
18361/// # Parameters
18362///
18363/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_json`].
18364/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_json`].
18365/// - `business_id`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_json`].
18366/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_edit_page_params_json`].
18367///
18368/// # Returns
18369///
18370/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_edit_page_params_json`] can produce a value and [`None`] otherwise.
18371///
18372/// # Examples
18373///
18374/// ```rust,ignore
18375/// let _result = pharos_native::runtime::json_commands::dynamic_business_edit_page_params_json(std::path::Path::new("."), "demo", todo!(), std::path::Path::new("apps/dev_docs"));
18376/// ```
18377///
18378/// # Related
18379///
18380/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18381pub fn dynamic_business_edit_page_params_json(
18382    root: &Value,
18383    business_slug: &str,
18384    business_id: i64,
18385    app_root: &Path,
18386) -> Option<String> {
18387    dynamic_business_edit_page_params_from_root_json_dup_local(
18388        root,
18389        business_slug,
18390        business_id,
18391        app_root,
18392    )
18393}
18394
18395/// Resolves one business media URL under the app-owned media directory.
18396///
18397/// # Parameters
18398///
18399/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_media_url`].
18400/// - `media_url`: Input consumed by [`crate::runtime::json_commands::dynamic_business_media_url`].
18401///
18402/// # Returns
18403///
18404/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_media_url`] can produce a value and [`None`] otherwise.
18405///
18406/// # Examples
18407///
18408/// ```rust,ignore
18409/// let _result = pharos_native::runtime::json_commands::dynamic_business_media_url("demo", todo!());
18410/// ```
18411///
18412/// # Related
18413///
18414/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18415pub fn dynamic_business_media_url(business_slug: &str, media_url: &str) -> Option<String> {
18416    if business_slug.is_empty() || media_url.is_empty() || media_url.contains(['\r', '\n']) {
18417        return None;
18418    }
18419    Some(format!(
18420        "/media/businesses/{}/{}",
18421        business_slug,
18422        media_url.trim_start_matches('/')
18423    ))
18424}
18425
18426/// Builds profile page parameters from persisted state.
18427///
18428/// # Parameters
18429///
18430/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_profile_page_params_json`].
18431/// - `user_id`: Input consumed by [`crate::runtime::json_commands::dynamic_profile_page_params_json`].
18432/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_profile_page_params_json`].
18433///
18434/// # Returns
18435///
18436/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_profile_page_params_json`] can produce a value and [`None`] otherwise.
18437///
18438/// # Examples
18439///
18440/// ```rust,ignore
18441/// let _result = pharos_native::runtime::json_commands::dynamic_profile_page_params_json(std::path::Path::new("."), 1, std::path::Path::new("apps/dev_docs"));
18442/// ```
18443///
18444/// # Related
18445///
18446/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18447pub fn dynamic_profile_page_params_json(
18448    root: &Value,
18449    user_id: i64,
18450    app_root: &Path,
18451) -> Option<String> {
18452    let user = state_row_by_i64(root, "users", "id", user_id)?;
18453    let full_name = user
18454        .get("full_name")
18455        .map(value_to_text)
18456        .filter(|value| !value.is_empty())
18457        .or_else(|| user.get("display_name").map(value_to_text))
18458        .unwrap_or_default();
18459    let email = user.get("email").map(value_to_text).unwrap_or_default();
18460    let phone_number = user
18461        .get("phone_number")
18462        .map(value_to_text)
18463        .unwrap_or_default();
18464    let address = user.get("address").map(value_to_text).unwrap_or_default();
18465    let payment_preference = user
18466        .get("payment_preference")
18467        .map(value_to_text)
18468        .filter(|value| !value.is_empty())
18469        .unwrap_or_else(|| "pay_on_site".to_owned());
18470    let google_status = bounded_state_array(root, "google_calendar_connections")
18471        .iter()
18472        .find(|row| row_i64_value(row, "user_id") == Some(user_id))
18473        .and_then(|row| row.get("connection_status"))
18474        .map(value_to_text)
18475        .filter(|value| !value.is_empty())
18476        .unwrap_or_else(|| "Disconnected".to_owned());
18477    let mut subscription_rows_html = String::new();
18478    for subscription in bounded_state_array(root, "subscriptions")
18479        .iter()
18480        .filter(|row| row_i64_value(row, "user_id") == Some(user_id))
18481    {
18482        let Some(business) = row_i64_value(subscription, "business_id")
18483            .and_then(|id| state_row_by_i64(root, "businesses", "id", id))
18484        else {
18485            continue;
18486        };
18487        let business_slug = business.get("slug").map(value_to_text).unwrap_or_default();
18488        if business_slug.is_empty() {
18489            continue;
18490        }
18491        let unsubscribe_button = render_fragment_with_params(
18492            app_root,
18493            "templates/shared/fragments/ui_button.html",
18494            Map::from_iter([
18495                (
18496                    "id".to_owned(),
18497                    Value::String(format!("profile-unsubscribe-{business_slug}")),
18498                ),
18499                ("type".to_owned(), Value::String("submit".to_owned())),
18500                (
18501                    "class_name".to_owned(),
18502                    Value::String("btn btn-danger btn-sm".to_owned()),
18503                ),
18504                ("attributes_html".to_owned(), Value::String(String::new())),
18505                (
18506                    "content".to_owned(),
18507                    Value::String("Unsubscribe".to_owned()),
18508                ),
18509            ]),
18510        )?;
18511        subscription_rows_html.push_str(&render_fragment_with_params(
18512            app_root,
18513            "templates/profile/fragments/subscription_row.html",
18514            Map::from_iter([
18515                ("business_slug".to_owned(), Value::String(business_slug)),
18516                (
18517                    "business_name".to_owned(),
18518                    Value::String(
18519                        business
18520                            .get("name")
18521                            .map(value_to_text)
18522                            .unwrap_or_else(|| "Business".to_owned()),
18523                    ),
18524                ),
18525                (
18526                    "profile_unsubscribe_button_ui_html".to_owned(),
18527                    Value::String(unsubscribe_button),
18528                ),
18529            ]),
18530        )?);
18531    }
18532    let subscriptions_empty = subscription_rows_html.is_empty();
18533    let subscriptions_empty_html = if subscriptions_empty {
18534        render_fragment_with_params(
18535            app_root,
18536            "templates/profile/fragments/subscriptions_empty.html",
18537            Map::new(),
18538        )?
18539    } else {
18540        String::new()
18541    };
18542    compact(&Value::Object(Map::from_iter([
18543        ("full_name".to_owned(), Value::String(full_name)),
18544        ("email".to_owned(), Value::String(email)),
18545        ("phone_number".to_owned(), Value::String(phone_number)),
18546        ("address".to_owned(), Value::String(address)),
18547        (
18548            "selected_payment_preference".to_owned(),
18549            Value::String(payment_preference),
18550        ),
18551        ("google_status".to_owned(), Value::String(google_status)),
18552        (
18553            "subscriptions_list_style".to_owned(),
18554            Value::String(if subscriptions_empty {
18555                "display:none;".to_owned()
18556            } else {
18557                String::new()
18558            }),
18559        ),
18560        (
18561            "subscription_rows_html".to_owned(),
18562            Value::String(subscription_rows_html),
18563        ),
18564        (
18565            "subscriptions_empty_style".to_owned(),
18566            Value::String(if subscriptions_empty {
18567                String::new()
18568            } else {
18569                "display:none;".to_owned()
18570            }),
18571        ),
18572        (
18573            "subscriptions_empty_html".to_owned(),
18574            Value::String(subscriptions_empty_html),
18575        ),
18576    ])))
18577}
18578
18579pub fn dynamic_booking_detail_page_params_from_root_json(
18580    root: &Value,
18581    user_id: i64,
18582    booking_id: i64,
18583) -> Option<String> {
18584    let booking = state_row_by_i64(root, "bookings", "id", booking_id)
18585        .filter(|row| row_i64_value(row, "user_id") == Some(user_id))?;
18586    let (date, time) = row_date_time(booking);
18587    compact(&Value::Object(Map::from_iter([
18588        (
18589            "booking_title".to_owned(),
18590            Value::String(
18591                booking
18592                    .get("title")
18593                    .map(value_to_text)
18594                    .filter(|value| !value.is_empty())
18595                    .unwrap_or_else(|| "Booking".to_owned()),
18596            ),
18597        ),
18598        ("date_value".to_owned(), Value::String(date)),
18599        (
18600            "time_value".to_owned(),
18601            Value::String(formatted_clock_time_business_logic_local(&time)),
18602        ),
18603        (
18604            "status_value".to_owned(),
18605            Value::String(
18606                booking
18607                    .get("status")
18608                    .map(value_to_text)
18609                    .filter(|value| !value.is_empty())
18610                    .unwrap_or_else(|| "confirmed".to_owned()),
18611            ),
18612        ),
18613    ])))
18614}
18615
18616pub fn dynamic_appointment_detail_page_params_from_root_json(
18617    root: &Value,
18618    user_id: i64,
18619    appointment_id: i64,
18620    app_root: &Path,
18621) -> Option<String> {
18622    let appointment = state_row_by_i64(root, "appointments", "id", appointment_id)?;
18623    let business = row_i64_value(appointment, "business_id")
18624        .and_then(|id| state_row_by_i64(root, "businesses", "id", id))?;
18625    let appointment_user_id = row_i64_value(appointment, "user_id").unwrap_or(0);
18626    let owner_id = row_i64_value(business, "owner_id").unwrap_or(0);
18627    if appointment_user_id != user_id && owner_id != user_id {
18628        return None;
18629    }
18630    let service = row_i64_value(appointment, "service_id")
18631        .and_then(|id| state_row_by_i64(root, "services", "id", id));
18632    let technician = row_i64_value(appointment, "technician_id")
18633        .and_then(|id| state_row_by_i64(root, "technicians", "id", id));
18634    let customer = state_row_by_i64(root, "users", "id", appointment_user_id);
18635    let (date, time) = row_date_time(appointment);
18636    let service_cost = appointment
18637        .get("service_cost")
18638        .map(value_to_text)
18639        .filter(|value| !value.is_empty());
18640    let service_cost_block = if let Some(cost) = service_cost.as_deref() {
18641        render_fragment_with_params(
18642            app_root,
18643            "templates/appointments/detail/fragments/service_cost_block.html",
18644            Map::from_iter([("service_cost".to_owned(), Value::String(cost.to_owned()))]),
18645        )?
18646    } else {
18647        String::new()
18648    };
18649    let notes = appointment
18650        .get("notes")
18651        .map(value_to_text)
18652        .unwrap_or_default();
18653    let notes_block = if notes.is_empty() {
18654        String::new()
18655    } else {
18656        render_fragment_with_params(
18657            app_root,
18658            "templates/appointments/detail/fragments/notes_block.html",
18659            Map::from_iter([("notes_text".to_owned(), Value::String(notes))]),
18660        )?
18661    };
18662    compact(&Value::Object(Map::from_iter([
18663        (
18664            "service_name".to_owned(),
18665            Value::String(
18666                service
18667                    .and_then(|row| row.get("name"))
18668                    .map(value_to_text)
18669                    .filter(|value| !value.is_empty())
18670                    .unwrap_or_else(|| "Appointment".to_owned()),
18671            ),
18672        ),
18673        (
18674            "business_slug".to_owned(),
18675            Value::String(business.get("slug").map(value_to_text).unwrap_or_default()),
18676        ),
18677        (
18678            "business_public_path".to_owned(),
18679            Value::String(format!(
18680                "/b/{}/",
18681                business.get("slug").map(value_to_text).unwrap_or_default()
18682            )),
18683        ),
18684        (
18685            "business_name".to_owned(),
18686            Value::String(
18687                business
18688                    .get("name")
18689                    .map(value_to_text)
18690                    .unwrap_or_else(|| "Business".to_owned()),
18691            ),
18692        ),
18693        ("date_value".to_owned(), Value::String(date)),
18694        (
18695            "time_value".to_owned(),
18696            Value::String(formatted_clock_time_business_logic_local(&time)),
18697        ),
18698        (
18699            "status_value".to_owned(),
18700            Value::String(
18701                appointment
18702                    .get("status")
18703                    .map(value_to_text)
18704                    .filter(|value| !value.is_empty())
18705                    .unwrap_or_else(|| "scheduled".to_owned()),
18706            ),
18707        ),
18708        (
18709            "technician_name".to_owned(),
18710            Value::String(
18711                technician
18712                    .and_then(|row| row.get("name"))
18713                    .map(value_to_text)
18714                    .filter(|value| !value.is_empty())
18715                    .unwrap_or_else(|| "Unassigned".to_owned()),
18716            ),
18717        ),
18718        (
18719            "duration_minutes".to_owned(),
18720            Value::String(
18721                appointment
18722                    .get("service_duration_minutes")
18723                    .map(value_to_text)
18724                    .filter(|value| !value.is_empty())
18725                    .unwrap_or_else(|| "45".to_owned()),
18726            ),
18727        ),
18728        (
18729            "customer_name".to_owned(),
18730            Value::String(
18731                customer
18732                    .and_then(|row| row.get("full_name").or_else(|| row.get("display_name")))
18733                    .map(value_to_text)
18734                    .filter(|value| !value.is_empty())
18735                    .unwrap_or_else(|| "Customer".to_owned()),
18736            ),
18737        ),
18738        (
18739            "customer_email".to_owned(),
18740            Value::String(
18741                customer
18742                    .and_then(|row| row.get("email"))
18743                    .map(value_to_text)
18744                    .unwrap_or_default(),
18745            ),
18746        ),
18747        (
18748            "customer_phone".to_owned(),
18749            Value::String(
18750                customer
18751                    .and_then(|row| row.get("phone_number"))
18752                    .map(value_to_text)
18753                    .filter(|value| !value.is_empty())
18754                    .unwrap_or_else(|| "Not provided".to_owned()),
18755            ),
18756        ),
18757        (
18758            "customer_address".to_owned(),
18759            Value::String(
18760                customer
18761                    .and_then(|row| row.get("address"))
18762                    .map(value_to_text)
18763                    .filter(|value| !value.is_empty())
18764                    .unwrap_or_else(|| "Not provided".to_owned()),
18765            ),
18766        ),
18767        (
18768            "service_cost_block".to_owned(),
18769            Value::String(service_cost_block),
18770        ),
18771        ("notes_block".to_owned(), Value::String(notes_block)),
18772    ])))
18773}
18774
18775/// Builds service booking form parameters from state.
18776///
18777/// # Parameters
18778///
18779/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`].
18780/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`].
18781/// - `service_id`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`].
18782/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`].
18783/// - `error_message`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`].
18784///
18785/// # Returns
18786///
18787/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json`] can produce a value and [`None`] otherwise.
18788///
18789/// # Examples
18790///
18791/// ```rust,ignore
18792/// let _result = pharos_native::runtime::json_commands::dynamic_service_book_form_page_params_from_root_json(std::path::Path::new("."), "demo", todo!(), std::path::Path::new("apps/dev_docs"), todo!());
18793/// ```
18794///
18795/// # Related
18796///
18797/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18798pub fn dynamic_service_book_form_page_params_from_root_json(
18799    root: &Value,
18800    business_slug: &str,
18801    service_id: i64,
18802    app_root: &Path,
18803    error_message: &str,
18804) -> Option<String> {
18805    let mut extra = Map::new();
18806    extra.insert("business_slug".into(), Value::String(business_slug.into()));
18807    extra.insert("service_id".into(), Value::from(service_id));
18808    extra.insert("error".into(), Value::String(error_message.into()));
18809    extra.insert(
18810        "app_root".into(),
18811        Value::String(app_root.to_string_lossy().into_owned()),
18812    );
18813    page_params_value(root, "service-book-form", extra)
18814}
18815
18816/// Builds service booking form parameters from state file.
18817///
18818/// # Parameters
18819///
18820/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`].
18821/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`].
18822/// - `service_id`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`].
18823/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`].
18824/// - `error_message`: Input consumed by [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`].
18825///
18826/// # Returns
18827///
18828/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_service_book_form_page_params_json`] can produce a value and [`None`] otherwise.
18829///
18830/// # Examples
18831///
18832/// ```rust,ignore
18833/// let _result = pharos_native::runtime::json_commands::dynamic_service_book_form_page_params_json(todo!(), "demo", todo!(), std::path::Path::new("apps/dev_docs"), todo!());
18834/// ```
18835///
18836/// # Related
18837///
18838/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18839pub fn dynamic_service_book_form_page_params_json(
18840    state_path: &Path,
18841    business_slug: &str,
18842    service_id: i64,
18843    app_root: &Path,
18844    error_message: &str,
18845) -> Option<String> {
18846    dynamic_service_book_form_page_params_from_root_json(
18847        &json_doc_load_file(state_path)?,
18848        business_slug,
18849        service_id,
18850        app_root,
18851        error_message,
18852    )
18853}
18854
18855/// Builds service edit parameters from state.
18856///
18857/// # Parameters
18858///
18859/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_from_root_json`].
18860/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_from_root_json`].
18861/// - `service_id`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_from_root_json`].
18862/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_from_root_json`].
18863///
18864/// # Returns
18865///
18866/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_service_edit_page_params_from_root_json`] can produce a value and [`None`] otherwise.
18867///
18868/// # Examples
18869///
18870/// ```rust,ignore
18871/// let _result = pharos_native::runtime::json_commands::dynamic_service_edit_page_params_from_root_json(std::path::Path::new("."), "demo", todo!(), std::path::Path::new("apps/dev_docs"));
18872/// ```
18873///
18874/// # Related
18875///
18876/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18877pub fn dynamic_service_edit_page_params_from_root_json(
18878    root: &Value,
18879    business_slug: &str,
18880    service_id: i64,
18881    app_root: &Path,
18882) -> Option<String> {
18883    let mut extra = Map::new();
18884    extra.insert("business_slug".into(), Value::String(business_slug.into()));
18885    extra.insert("service_id".into(), Value::from(service_id));
18886    extra.insert(
18887        "app_root".into(),
18888        Value::String(app_root.to_string_lossy().into_owned()),
18889    );
18890    page_params_value(root, "service-edit", extra)
18891}
18892
18893/// Builds service edit parameters from state file.
18894///
18895/// # Parameters
18896///
18897/// - `state_path`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_json`].
18898/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_json`].
18899/// - `service_id`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_json`].
18900/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_service_edit_page_params_json`].
18901///
18902/// # Returns
18903///
18904/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_service_edit_page_params_json`] can produce a value and [`None`] otherwise.
18905///
18906/// # Examples
18907///
18908/// ```rust,ignore
18909/// let _result = pharos_native::runtime::json_commands::dynamic_service_edit_page_params_json(todo!(), "demo", todo!(), std::path::Path::new("apps/dev_docs"));
18910/// ```
18911///
18912/// # Related
18913///
18914/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
18915pub fn dynamic_service_edit_page_params_json(
18916    state_path: &Path,
18917    business_slug: &str,
18918    service_id: i64,
18919    app_root: &Path,
18920) -> Option<String> {
18921    dynamic_service_edit_page_params_from_root_json(
18922        &json_doc_load_file(state_path)?,
18923        business_slug,
18924        service_id,
18925        app_root,
18926    )
18927}
18928
18929/// Performs rating score f64.
18930fn rating_score_f64(value: &Value) -> f64 {
18931    value
18932        .as_f64()
18933        .or_else(|| value.as_i64().map(|number| number as f64))
18934        .unwrap_or(0.0)
18935}
18936
18937/// Performs rating score label.
18938fn rating_score_label(score: f64) -> String {
18939    if (score.fract()).abs() < 0.000_001 {
18940        format!("{score:.0}/5")
18941    } else {
18942        format!("{score:.1}/5")
18943    }
18944}
18945
18946/// Performs rating stars HTML.
18947fn rating_stars_html(app_root: &Path, score: f64) -> Option<String> {
18948    let clamped = score.clamp(0.0, 5.0);
18949    let full = clamped.floor() as usize;
18950    let has_half = (clamped - full as f64) >= 0.5;
18951    let empty = 5usize.saturating_sub(full + usize::from(has_half));
18952    let mut out = String::new();
18953    for _ in 0..full {
18954        out.push_str(&render_fragment_with_params(
18955            app_root,
18956            "templates/businesses/fragments/business_rating_star.html",
18957            Map::from_iter([(
18958                "class_name".to_owned(),
18959                Value::String("bi-star-fill".to_owned()),
18960            )]),
18961        )?);
18962    }
18963    if has_half {
18964        out.push_str(&render_fragment_with_params(
18965            app_root,
18966            "templates/businesses/fragments/business_rating_star.html",
18967            Map::from_iter([(
18968                "class_name".to_owned(),
18969                Value::String("bi-star-half".to_owned()),
18970            )]),
18971        )?);
18972    }
18973    for _ in 0..empty {
18974        out.push_str(&render_fragment_with_params(
18975            app_root,
18976            "templates/businesses/fragments/business_rating_star.html",
18977            Map::from_iter([("class_name".to_owned(), Value::String("bi-star".to_owned()))]),
18978        )?);
18979    }
18980    Some(out)
18981}
18982
18983/// Builds the business landing page parameters.
18984///
18985/// # Parameters
18986///
18987/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_landing_page_params_json`].
18988/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_business_landing_page_params_json`].
18989/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_business_landing_page_params_json`].
18990///
18991/// # Returns
18992///
18993/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_business_landing_page_params_json`] can produce a value and [`None`] otherwise.
18994///
18995/// # Performance
18996///
18997/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_business_landing_page_params_json`].
18998///
18999/// # Examples
19000///
19001/// ```rust,ignore
19002/// let _result = pharos_native::runtime::json_commands::dynamic_business_landing_page_params_json(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
19003/// ```
19004///
19005/// # Related
19006///
19007/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19008pub fn dynamic_business_landing_page_params_json(
19009    root: &Value,
19010    business_slug: &str,
19011    app_root: &Path,
19012) -> Option<String> {
19013    let business = generated::dynamic_find_business_by_slug(root, business_slug)?;
19014    let business_id = business.get("id").and_then(Value::as_i64)?;
19015    let business_name = value_to_text(business.get("name").unwrap_or(&Value::Null));
19016    let description = value_to_text(business.get("description").unwrap_or(&Value::Null));
19017    let secondary_color = business
19018        .get("secondary_color")
19019        .and_then(Value::as_str)
19020        .filter(|value| value.len() == 7 && value.starts_with('#'))
19021        .unwrap_or("#e5e7eb");
19022    let hero_style = format!(
19023        "background:{secondary_color};color:{};",
19024        contrast_text_color_business_logic_local(secondary_color)
19025    );
19026
19027    let image_html = business
19028        .get("image_url")
19029        .and_then(Value::as_str)
19030        .filter(|value| !value.is_empty())
19031        .and_then(|image_url| {
19032            render_app_fragment_from_doc(
19033                &app_root.to_string_lossy(),
19034                "templates/businesses/fragments/business_landing_image.html",
19035                &Value::Object(Map::from_iter([
19036                    ("image_url".to_owned(), Value::String(image_url.to_owned())),
19037                    ("image_alt".to_owned(), Value::String(business_name.clone())),
19038                ])),
19039            )
19040        })
19041        .unwrap_or_default();
19042
19043    let cta_html = render_app_fragment_from_doc(
19044        &app_root.to_string_lossy(),
19045        "templates/businesses/fragments/business_logged_out_cta.html",
19046        &Value::Object(Map::from_iter([(
19047            "business_slug".to_owned(),
19048            Value::String(business_slug.to_owned()),
19049        )])),
19050    )
19051    .unwrap_or_default();
19052
19053    let mut service_cards_html = String::new();
19054    let mut services = bounded_state_array(root, "services")
19055        .iter()
19056        .filter(|service| {
19057            service.get("business_id").and_then(Value::as_i64) == Some(business_id)
19058                && service
19059                    .get("is_active")
19060                    .and_then(Value::as_bool)
19061                    .unwrap_or(true)
19062        })
19063        .collect::<Vec<_>>();
19064    services.sort_by_key(|service| {
19065        service
19066            .get("sort_order")
19067            .and_then(Value::as_i64)
19068            .unwrap_or(i64::MAX)
19069    });
19070    for service in services.into_iter().take(MAX_OUTPUT_ROWS_JSON) {
19071        let service_id = service
19072            .get("id")
19073            .and_then(Value::as_i64)
19074            .unwrap_or_default();
19075        let service_name = value_to_text(service.get("name").unwrap_or(&Value::Null));
19076        let image_url = service
19077            .get("image_url")
19078            .or_else(|| service.get("image"))
19079            .map(value_to_text)
19080            .unwrap_or_default();
19081        let primary_color = service
19082            .get("primary_color")
19083            .and_then(Value::as_str)
19084            .filter(|value| !value.is_empty());
19085        let visual_html =
19086            service_visual_html(app_root, Some(&image_url), &service_name, primary_color)
19087                .unwrap_or_default();
19088        let card_params = Value::Object(Map::from_iter([
19089            (
19090                "business_slug".to_owned(),
19091                Value::String(business_slug.to_owned()),
19092            ),
19093            ("service_id".to_owned(), Value::from(service_id)),
19094            ("service_visual_html".to_owned(), Value::String(visual_html)),
19095            ("service_name".to_owned(), Value::String(service_name)),
19096            (
19097                "service_duration_minutes".to_owned(),
19098                Value::from(
19099                    service
19100                        .get("duration_minutes")
19101                        .and_then(Value::as_i64)
19102                        .unwrap_or(45),
19103                ),
19104            ),
19105            (
19106                "service_cost".to_owned(),
19107                Value::String(value_to_text(service.get("cost").unwrap_or(&Value::Null))),
19108            ),
19109            (
19110                "service_description".to_owned(),
19111                Value::String(value_to_text(
19112                    service.get("description").unwrap_or(&Value::Null),
19113                )),
19114            ),
19115        ]));
19116        if let Some(card) = render_app_fragment_from_doc(
19117            &app_root.to_string_lossy(),
19118            "templates/businesses/fragments/business_service_card.html",
19119            &card_params,
19120        ) {
19121            service_cards_html.push_str(&card);
19122        }
19123    }
19124    if service_cards_html.is_empty() {
19125        service_cards_html = render_fragment_with_params(
19126            app_root,
19127            "templates/businesses/fragments/business_services_empty.html",
19128            Map::new(),
19129        )?;
19130    }
19131
19132    let mut rating_rows_html = String::new();
19133    for rating in bounded_state_array(root, "ratings")
19134        .iter()
19135        .filter(|rating| rating.get("business_id").and_then(Value::as_i64) == Some(business_id))
19136        .take(MAX_OUTPUT_ROWS_JSON)
19137    {
19138        let score = rating_score_f64(rating.get("score").unwrap_or(&Value::Null));
19139        if let Some(row) = render_app_fragment_from_doc(
19140            &app_root.to_string_lossy(),
19141            "templates/businesses/fragments/business_rating_row.html",
19142            &Value::Object(Map::from_iter([
19143                (
19144                    "rating_score_label".to_owned(),
19145                    Value::String(rating_score_label(score)),
19146                ),
19147                (
19148                    "rating_stars_html".to_owned(),
19149                    Value::String(rating_stars_html(app_root, score)?),
19150                ),
19151                (
19152                    "rating_comment".to_owned(),
19153                    Value::String(value_to_text(rating.get("comment").unwrap_or(&Value::Null))),
19154                ),
19155            ])),
19156        ) {
19157            rating_rows_html.push_str(&row);
19158        }
19159    }
19160    if rating_rows_html.is_empty() {
19161        rating_rows_html = render_fragment_with_params(
19162            app_root,
19163            "templates/businesses/fragments/business_ratings_empty.html",
19164            Map::new(),
19165        )?;
19166    }
19167
19168    compact(&Value::Object(Map::from_iter([
19169        (
19170            "business_slug".to_owned(),
19171            Value::String(business_slug.to_owned()),
19172        ),
19173        ("business_name".to_owned(), Value::String(business_name)),
19174        (
19175            "business_description".to_owned(),
19176            Value::String(description),
19177        ),
19178        ("hero_style".to_owned(), Value::String(hero_style)),
19179        (
19180            "private_badge_html".to_owned(),
19181            Value::String(String::new()),
19182        ),
19183        ("business_image_html".to_owned(), Value::String(image_html)),
19184        ("cta_html".to_owned(), Value::String(cta_html)),
19185        (
19186            "service_cards_html".to_owned(),
19187            Value::String(service_cards_html),
19188        ),
19189        (
19190            "rating_rows_html".to_owned(),
19191            Value::String(rating_rows_html),
19192        ),
19193    ])))
19194}
19195
19196/// Builds the diagnostics page parameters.
19197///
19198/// # Parameters
19199///
19200/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_diagnostics_page_params_json`].
19201/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_diagnostics_page_params_json`].
19202///
19203/// # Returns
19204///
19205/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_diagnostics_page_params_json`] can produce a value and [`None`] otherwise.
19206///
19207/// # Examples
19208///
19209/// ```rust,ignore
19210/// let _result = pharos_native::runtime::json_commands::dynamic_diagnostics_page_params_json(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"));
19211/// ```
19212///
19213/// # Related
19214///
19215/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19216pub fn dynamic_diagnostics_page_params_json(root: &Value, app_root: &Path) -> Option<String> {
19217    let mut extra = Map::new();
19218    extra.insert(
19219        "app_root".into(),
19220        Value::String(app_root.to_string_lossy().into_owned()),
19221    );
19222    extra.insert(
19223        "audit_events".into(),
19224        Value::Array(bounded_state_array(root, "audit_events").to_vec()),
19225    );
19226    page_params_value(root, "diagnostics", extra)
19227}
19228
19229/// Renders diagnostics page params.
19230///
19231/// # Parameters
19232///
19233/// - `root`: Input consumed by [`crate::runtime::json_commands::render_diagnostics_page_params`].
19234/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_diagnostics_page_params`].
19235///
19236/// # Returns
19237///
19238/// Returns [`Some`] when [`crate::runtime::json_commands::render_diagnostics_page_params`] can produce a value and [`None`] otherwise.
19239///
19240/// # Examples
19241///
19242/// ```rust,ignore
19243/// let _result = pharos_native::runtime::json_commands::render_diagnostics_page_params(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"));
19244/// ```
19245///
19246/// # Related
19247///
19248/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19249pub fn render_diagnostics_page_params(root: &Value, app_root: &Path) -> Option<String> {
19250    dynamic_diagnostics_page_params_json(root, app_root)
19251}
19252
19253/// Builds the explore page parameters.
19254///
19255/// # Parameters
19256///
19257/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_explore_page_params_json`].
19258/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_explore_page_params_json`].
19259///
19260/// # Returns
19261///
19262/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_explore_page_params_json`] can produce a value and [`None`] otherwise.
19263///
19264/// # Examples
19265///
19266/// ```rust,ignore
19267/// let _result = pharos_native::runtime::json_commands::dynamic_explore_page_params_json(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"));
19268/// ```
19269///
19270/// # Related
19271///
19272/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19273pub fn dynamic_explore_page_params_json(root: &Value, app_root: &Path) -> Option<String> {
19274    let mut extra = Map::new();
19275    extra.insert(
19276        "app_root".into(),
19277        Value::String(app_root.to_string_lossy().into_owned()),
19278    );
19279    extra.insert(
19280        "businesses".into(),
19281        Value::Array(bounded_state_array(root, "businesses").to_vec()),
19282    );
19283    page_params_value(root, "explore", extra)
19284}
19285
19286/// Builds a job-queue detail page parameter document.
19287///
19288/// # Parameters
19289///
19290/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_detail_page_params_json`].
19291/// - `job_id`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_detail_page_params_json`].
19292/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_detail_page_params_json`].
19293///
19294/// # Returns
19295///
19296/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_job_queue_detail_page_params_json`] can produce a value and [`None`] otherwise.
19297///
19298/// # Performance
19299///
19300/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_job_queue_detail_page_params_json`].
19301///
19302/// # Examples
19303///
19304/// ```rust,ignore
19305/// let _result = pharos_native::runtime::json_commands::dynamic_job_queue_detail_page_params_json(std::path::Path::new("."), todo!(), std::path::Path::new("apps/dev_docs"));
19306/// ```
19307///
19308/// # Related
19309///
19310/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19311pub fn dynamic_job_queue_detail_page_params_json(
19312    root: &Value,
19313    job_id: i64,
19314    app_root: &Path,
19315) -> Option<String> {
19316    let mut extra = Map::new();
19317    extra.insert("job_id".into(), Value::from(job_id));
19318    extra.insert(
19319        "app_root".into(),
19320        Value::String(app_root.to_string_lossy().into_owned()),
19321    );
19322    extra.insert(
19323        "job".into(),
19324        bounded_state_array(root, "job_executions")
19325            .iter()
19326            .find(|row| row.get("id").and_then(Value::as_i64) == Some(job_id))
19327            .cloned()
19328            .unwrap_or(Value::Null),
19329    );
19330    page_params_value(root, "job-queue-detail", extra)
19331}
19332
19333/// Builds bounded, app-fragment-backed job-queue list page parameters.
19334///
19335/// # Parameters
19336///
19337/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_list_page_params_json`].
19338/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_list_page_params_json`].
19339/// - `query_string`: Input consumed by [`crate::runtime::json_commands::dynamic_job_queue_list_page_params_json`].
19340///
19341/// # Returns
19342///
19343/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_job_queue_list_page_params_json`] can produce a value and [`None`] otherwise.
19344///
19345/// # Performance
19346///
19347/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_job_queue_list_page_params_json`].
19348///
19349/// # Examples
19350///
19351/// ```rust,ignore
19352/// let _result = pharos_native::runtime::json_commands::dynamic_job_queue_list_page_params_json(std::path::Path::new("."), std::path::Path::new("apps/dev_docs"), "page=1");
19353/// ```
19354///
19355/// # Related
19356///
19357/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19358pub fn dynamic_job_queue_list_page_params_json(
19359    root: &Value,
19360    app_root: &Path,
19361    query_string: &str,
19362) -> Option<String> {
19363    const PAGE_SIZE: usize = 20;
19364    let requested_status = request_query_value(query_string, "status").unwrap_or_default();
19365    let status_filter = match requested_status.as_str() {
19366        "queued" | "running" | "succeeded" | "failed" | "cancelled" => requested_status,
19367        _ => String::new(),
19368    };
19369    let search_query = request_query_value(query_string, "q")
19370        .unwrap_or_default()
19371        .chars()
19372        .take(160)
19373        .collect::<String>();
19374    let requested_page = request_query_value(query_string, "page")
19375        .and_then(|value| value.parse::<usize>().ok())
19376        .filter(|value| *value > 0)
19377        .unwrap_or(1)
19378        .min(1_000_000);
19379    let jobs = bounded_state_array(root, "job_executions");
19380    let mut queued_count = 0_usize;
19381    let mut running_count = 0_usize;
19382    let mut succeeded_count = 0_usize;
19383    let mut failed_count = 0_usize;
19384    let mut cancelled_count = 0_usize;
19385    let matches_filters = |row: &Value| {
19386        let status = row
19387            .get("execution_status")
19388            .and_then(Value::as_str)
19389            .unwrap_or_default();
19390        (status_filter.is_empty() || status == status_filter)
19391            && (search_query.is_empty()
19392                || row
19393                    .get("job_id")
19394                    .map(value_to_text)
19395                    .is_some_and(|value| value.contains(&search_query))
19396                || row
19397                    .get("handler_id")
19398                    .map(value_to_text)
19399                    .is_some_and(|value| value.contains(&search_query)))
19400    };
19401    let mut matched_count = 0_usize;
19402    for row in jobs.iter().filter(|row| row.is_object()) {
19403        let status = row
19404            .get("execution_status")
19405            .and_then(Value::as_str)
19406            .unwrap_or_default();
19407        match status {
19408            "queued" => queued_count += 1,
19409            "running" => running_count += 1,
19410            "succeeded" => succeeded_count += 1,
19411            "failed" => failed_count += 1,
19412            "cancelled" => cancelled_count += 1,
19413            _ => {}
19414        }
19415        if matches_filters(row) {
19416            matched_count += 1;
19417        }
19418    }
19419    let supplied_page = root.get("_job_page");
19420    if let Some(metadata) = supplied_page {
19421        let count = |status: &str| {
19422            metadata
19423                .get("counts")?
19424                .get(status)?
19425                .as_u64()
19426                .and_then(|count| usize::try_from(count).ok())
19427        };
19428        queued_count = count("queued")?;
19429        running_count = count("running")?;
19430        succeeded_count = count("succeeded")?;
19431        failed_count = count("failed")?;
19432        cancelled_count = count("cancelled")?;
19433        matched_count = usize::try_from(metadata.get("matched_count")?.as_u64()?).ok()?;
19434    }
19435    let page_count = matched_count.div_ceil(PAGE_SIZE).max(1);
19436    let page = if let Some(metadata) = supplied_page {
19437        usize::try_from(metadata.get("page")?.as_u64()?).ok()?
19438    } else {
19439        requested_page.min(page_count)
19440    };
19441    let start = if supplied_page.is_some() {
19442        0
19443    } else {
19444        (page - 1) * PAGE_SIZE
19445    };
19446    let mut job_rows = String::new();
19447    for row in jobs
19448        .iter()
19449        .filter(|row| row.is_object() && matches_filters(row))
19450        .skip(start)
19451        .take(PAGE_SIZE)
19452    {
19453        let job_id = row.get("id").and_then(Value::as_i64).unwrap_or_default();
19454        let status = row
19455            .get("execution_status")
19456            .and_then(Value::as_str)
19457            .unwrap_or_default();
19458        let action_buttons = if matches!(status, "queued" | "running") {
19459            let button = render_fragment_with_params(
19460                app_root,
19461                "templates/shared/fragments/ui_button.html",
19462                Map::from_iter([
19463                    (
19464                        "id".to_owned(),
19465                        Value::String(format!("job-cancel-{job_id}")),
19466                    ),
19467                    ("button_type".to_owned(), Value::String("submit".to_owned())),
19468                    (
19469                        "class_name".to_owned(),
19470                        Value::String("btn btn-danger btn-sm".to_owned()),
19471                    ),
19472                    ("attributes_html".to_owned(), Value::String(String::new())),
19473                    (
19474                        "content_html".to_owned(),
19475                        Value::String("Cancel".to_owned()),
19476                    ),
19477                ]),
19478            )?;
19479            render_fragment_with_params(
19480                app_root,
19481                "templates/queue/fragments/job_cancel_action.html",
19482                Map::from_iter([
19483                    ("job_id_path".to_owned(), Value::from(job_id)),
19484                    (
19485                        "job_cancel_button_ui_html".to_owned(),
19486                        Value::String(button),
19487                    ),
19488                ]),
19489            )?
19490        } else if matches!(status, "failed" | "cancelled") {
19491            let button = render_fragment_with_params(
19492                app_root,
19493                "templates/shared/fragments/ui_button.html",
19494                Map::from_iter([
19495                    (
19496                        "id".to_owned(),
19497                        Value::String(format!("job-retry-{job_id}")),
19498                    ),
19499                    ("button_type".to_owned(), Value::String("submit".to_owned())),
19500                    (
19501                        "class_name".to_owned(),
19502                        Value::String("btn btn-secondary btn-sm".to_owned()),
19503                    ),
19504                    ("attributes_html".to_owned(), Value::String(String::new())),
19505                    ("content_html".to_owned(), Value::String("Retry".to_owned())),
19506                ]),
19507            )?;
19508            render_fragment_with_params(
19509                app_root,
19510                "templates/queue/fragments/job_retry_action.html",
19511                Map::from_iter([
19512                    ("job_id_path".to_owned(), Value::from(job_id)),
19513                    ("job_retry_button_ui_html".to_owned(), Value::String(button)),
19514                ]),
19515            )?
19516        } else {
19517            String::new()
19518        };
19519        job_rows.push_str(&render_fragment_with_params(
19520            app_root,
19521            "templates/queue/fragments/job_row.html",
19522            Map::from_iter([
19523                ("job_id_path".to_owned(), Value::from(job_id)),
19524                ("job_id_text".to_owned(), Value::from(job_id)),
19525                (
19526                    "job_key".to_owned(),
19527                    Value::String(row.get("job_id").map(value_to_text).unwrap_or_default()),
19528                ),
19529                (
19530                    "handler_id".to_owned(),
19531                    Value::String(row.get("handler_id").map(value_to_text).unwrap_or_default()),
19532                ),
19533                ("job_status".to_owned(), Value::String(status.to_owned())),
19534                (
19535                    "attempt_count".to_owned(),
19536                    Value::from(
19537                        row.get("attempt_count")
19538                            .and_then(Value::as_i64)
19539                            .unwrap_or_default(),
19540                    ),
19541                ),
19542                (
19543                    "max_attempts".to_owned(),
19544                    Value::from(
19545                        row.get("max_attempts")
19546                            .and_then(Value::as_i64)
19547                            .unwrap_or_default(),
19548                    ),
19549                ),
19550                (
19551                    "created_at".to_owned(),
19552                    Value::String(row.get("created_at").map(value_to_text).unwrap_or_default()),
19553                ),
19554                ("action_buttons".to_owned(), Value::String(action_buttons)),
19555            ]),
19556        )?);
19557    }
19558    if job_rows.is_empty() {
19559        job_rows = render_fragment_with_params(
19560            app_root,
19561            "templates/queue/fragments/job_empty_row.html",
19562            Map::from_iter([(
19563                "message".to_owned(),
19564                Value::String("No jobs match the current filter.".to_owned()),
19565            )]),
19566        )?;
19567    }
19568    let mut pager = String::new();
19569    let status_query_html = if status_filter.is_empty() {
19570        String::new()
19571    } else {
19572        render_fragment_with_params(
19573            app_root,
19574            "templates/queue/fragments/job_query_suffix.html",
19575            Map::from_iter([
19576                ("query_name".to_owned(), Value::String("status".to_owned())),
19577                (
19578                    "query_value".to_owned(),
19579                    Value::String(url_encode_query_component(&status_filter)),
19580                ),
19581            ]),
19582        )?
19583        .trim()
19584        .to_owned()
19585    };
19586    let search_query_html = if search_query.is_empty() {
19587        String::new()
19588    } else {
19589        render_fragment_with_params(
19590            app_root,
19591            "templates/queue/fragments/job_query_suffix.html",
19592            Map::from_iter([
19593                ("query_name".to_owned(), Value::String("q".to_owned())),
19594                (
19595                    "query_value".to_owned(),
19596                    Value::String(url_encode_query_component(&search_query)),
19597                ),
19598            ]),
19599        )?
19600        .trim()
19601        .to_owned()
19602    };
19603    for (link_page, label, trailing_space) in [
19604        (
19605            page.checked_sub(1).filter(|value| *value > 0),
19606            "← Prev",
19607            page < page_count,
19608        ),
19609        ((page < page_count).then_some(page + 1), "Next →", false),
19610    ] {
19611        let Some(link_page) = link_page else {
19612            continue;
19613        };
19614        pager.push_str(&render_fragment_with_params(
19615            app_root,
19616            "templates/queue/fragments/job_pager_link.html",
19617            Map::from_iter([
19618                ("page_number".to_owned(), Value::from(link_page)),
19619                (
19620                    "status_query_html".to_owned(),
19621                    Value::String(status_query_html.clone()),
19622                ),
19623                (
19624                    "search_query_html".to_owned(),
19625                    Value::String(search_query_html.clone()),
19626                ),
19627                ("link_label".to_owned(), Value::String(label.to_owned())),
19628                (
19629                    "trailing_space".to_owned(),
19630                    Value::String(if trailing_space { " " } else { "" }.to_owned()),
19631                ),
19632            ]),
19633        )?);
19634    }
19635    compact(&Value::Object(Map::from_iter([
19636        ("queued_count".to_owned(), Value::from(queued_count)),
19637        ("running_count".to_owned(), Value::from(running_count)),
19638        ("succeeded_count".to_owned(), Value::from(succeeded_count)),
19639        ("failed_count".to_owned(), Value::from(failed_count)),
19640        ("cancelled_count".to_owned(), Value::from(cancelled_count)),
19641        ("page".to_owned(), Value::from(page)),
19642        ("page_count".to_owned(), Value::from(page_count)),
19643        ("status_filter".to_owned(), Value::String(status_filter)),
19644        ("search_query".to_owned(), Value::String(search_query)),
19645        ("job_rows".to_owned(), Value::String(job_rows)),
19646        ("pager".to_owned(), Value::String(pager)),
19647    ])))
19648}
19649
19650/// Renders the declared service visual fragment with escaped data.
19651///
19652/// # Parameters
19653///
19654/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_render_service_visual_html`].
19655/// - `service`: Input consumed by [`crate::runtime::json_commands::dynamic_render_service_visual_html`].
19656///
19657/// # Returns
19658///
19659/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_render_service_visual_html`] can produce a value and [`None`] otherwise.
19660///
19661/// # Examples
19662///
19663/// ```rust,ignore
19664/// let _result = pharos_native::runtime::json_commands::dynamic_render_service_visual_html(std::path::Path::new("apps/dev_docs"), todo!());
19665/// ```
19666///
19667/// # Related
19668///
19669/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19670pub fn dynamic_render_service_visual_html(app_root: &Path, service: &Value) -> Option<String> {
19671    let name = value_to_text(service.get("name").unwrap_or(&Value::Null));
19672    let image = service
19673        .get("image_url")
19674        .map(value_to_text)
19675        .unwrap_or_default();
19676    let color = service
19677        .get("primary_color")
19678        .map(value_to_text)
19679        .filter(|value| !value.is_empty());
19680    service_visual_html(app_root, Some(&image), &name, color.as_deref())
19681}
19682
19683/// Renders a workspace panel.
19684///
19685/// # Parameters
19686///
19687/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19688/// - `panel_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19689/// - `header_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19690/// - `title_text`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19691/// - `header_actions_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19692/// - `body_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`].
19693///
19694/// # Returns
19695///
19696/// Returns [`Some`] when [`crate::runtime::json_commands::render_workspace_panel_html_business_logic_local`] can produce a value and [`None`] otherwise.
19697///
19698/// # Examples
19699///
19700/// ```rust,ignore
19701/// let _result = pharos_native::runtime::json_commands::render_workspace_panel_html_business_logic_local(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!());
19702/// ```
19703///
19704/// # Related
19705///
19706/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19707pub fn render_workspace_panel_html_business_logic_local(
19708    app_root: &Path,
19709    panel_class: &str,
19710    header_class: &str,
19711    title_text: &str,
19712    header_actions_html: &str,
19713    body_html: &str,
19714) -> Option<String> {
19715    render_fragment_with_params(
19716        app_root,
19717        "templates/shared/fragments/workspace_panel.html",
19718        Map::from_iter([
19719            (
19720                "panel_class".to_owned(),
19721                Value::String(panel_class.to_owned()),
19722            ),
19723            (
19724                "header_class".to_owned(),
19725                Value::String(header_class.to_owned()),
19726            ),
19727            (
19728                "title_text".to_owned(),
19729                Value::String(title_text.to_owned()),
19730            ),
19731            (
19732                "header_actions_html".to_owned(),
19733                Value::String(header_actions_html.to_owned()),
19734            ),
19735            ("body_html".to_owned(), Value::String(body_html.to_owned())),
19736        ]),
19737    )
19738}
19739
19740/// Renders two workspace panels in a bounded grid.
19741///
19742/// # Parameters
19743///
19744/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_workspace_split_grid_html_business_logic_local`].
19745/// - `grid_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_split_grid_html_business_logic_local`].
19746/// - `left_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_split_grid_html_business_logic_local`].
19747/// - `right_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_split_grid_html_business_logic_local`].
19748///
19749/// # Returns
19750///
19751/// Returns [`Some`] when [`crate::runtime::json_commands::render_workspace_split_grid_html_business_logic_local`] can produce a value and [`None`] otherwise.
19752///
19753/// # Examples
19754///
19755/// ```rust,ignore
19756/// let _result = pharos_native::runtime::json_commands::render_workspace_split_grid_html_business_logic_local(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
19757/// ```
19758///
19759/// # Related
19760///
19761/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19762pub fn render_workspace_split_grid_html_business_logic_local(
19763    app_root: &Path,
19764    grid_class: &str,
19765    left_html: &str,
19766    right_html: &str,
19767) -> Option<String> {
19768    render_fragment_with_params(
19769        app_root,
19770        "templates/shared/fragments/workspace_split_grid.html",
19771        Map::from_iter([
19772            (
19773                "grid_class".to_owned(),
19774                Value::String(grid_class.to_owned()),
19775            ),
19776            ("left_html".to_owned(), Value::String(left_html.to_owned())),
19777            (
19778                "right_html".to_owned(),
19779                Value::String(right_html.to_owned()),
19780            ),
19781        ]),
19782    )
19783}
19784
19785/// Renders a workspace dialog with app-owned inner fragments.
19786///
19787/// # Parameters
19788///
19789/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19790/// - `dialog_id`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19791/// - `dialog_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19792/// - `shell_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19793/// - `copy_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19794/// - `copy_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19795/// - `actions_class`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19796/// - `actions_html`: Input consumed by [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`].
19797///
19798/// # Returns
19799///
19800/// Returns [`Some`] when [`crate::runtime::json_commands::render_workspace_dialog_html_business_logic_local`] can produce a value and [`None`] otherwise.
19801///
19802/// # Examples
19803///
19804/// ```rust,ignore
19805/// let _result = pharos_native::runtime::json_commands::render_workspace_dialog_html_business_logic_local(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!(), todo!(), todo!(), todo!());
19806/// ```
19807///
19808/// # Related
19809///
19810/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19811pub fn render_workspace_dialog_html_business_logic_local(
19812    app_root: &Path,
19813    dialog_id: &str,
19814    dialog_class: &str,
19815    shell_class: &str,
19816    copy_class: &str,
19817    copy_html: &str,
19818    actions_class: &str,
19819    actions_html: &str,
19820) -> Option<String> {
19821    render_fragment_with_params(
19822        app_root,
19823        "templates/shared/fragments/workspace_dialog.html",
19824        Map::from_iter([
19825            ("dialog_id".to_owned(), Value::String(dialog_id.to_owned())),
19826            (
19827                "dialog_class".to_owned(),
19828                Value::String(dialog_class.to_owned()),
19829            ),
19830            (
19831                "shell_class".to_owned(),
19832                Value::String(shell_class.to_owned()),
19833            ),
19834            (
19835                "copy_class".to_owned(),
19836                Value::String(copy_class.to_owned()),
19837            ),
19838            ("copy_html".to_owned(), Value::String(copy_html.to_owned())),
19839            (
19840                "actions_class".to_owned(),
19841                Value::String(actions_class.to_owned()),
19842            ),
19843            (
19844                "actions_html".to_owned(),
19845                Value::String(actions_html.to_owned()),
19846            ),
19847        ]),
19848    )
19849}
19850
19851/// Returns the calendar color contrast text.
19852///
19853/// # Parameters
19854///
19855/// - `background`: Input consumed by [`crate::runtime::json_commands::contrast_text_color_business_logic_local`].
19856///
19857/// # Returns
19858///
19859/// Returns the computed value produced by [`crate::runtime::json_commands::contrast_text_color_business_logic_local`].
19860///
19861/// # Examples
19862///
19863/// ```rust,ignore
19864/// let _result = pharos_native::runtime::json_commands::contrast_text_color_business_logic_local(todo!());
19865/// ```
19866///
19867/// # Related
19868///
19869/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19870pub fn contrast_text_color_business_logic_local(background: &str) -> &'static str {
19871    let hex = background.trim_start_matches('#');
19872    let value = u32::from_str_radix(hex, 16).unwrap_or(0xffffff);
19873    let red = (value >> 16) & 0xff;
19874    let green = (value >> 8) & 0xff;
19875    let blue = value & 0xff;
19876    if red * 299 + green * 587 + blue * 114 >= 128000 {
19877        "#111827"
19878    } else {
19879        "#ffffff"
19880    }
19881}
19882
19883/// Returns service-name initials, treating parentheses and whitespace as word separators.
19884///
19885/// # Parameters
19886///
19887/// - `name`: Input consumed by [`crate::runtime::json_commands::dynamic_service_abbreviation`].
19888///
19889/// # Returns
19890///
19891/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_service_abbreviation`].
19892///
19893/// # Performance
19894///
19895/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_service_abbreviation`].
19896///
19897/// # Examples
19898///
19899/// ```rust,ignore
19900/// let _result = pharos_native::runtime::json_commands::dynamic_service_abbreviation("name");
19901/// ```
19902///
19903/// # Related
19904///
19905/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19906pub fn dynamic_service_abbreviation(name: &str) -> String {
19907    name.split(|character: char| character.is_whitespace() || matches!(character, '(' | ')'))
19908        .filter_map(|word| word.chars().next())
19909        .collect::<String>()
19910        .to_uppercase()
19911}
19912
19913/// Returns a safe service badge color.
19914///
19915/// # Parameters
19916///
19917/// - `primary_color`: Input consumed by [`crate::runtime::json_commands::dynamic_service_badge_color`].
19918///
19919/// # Returns
19920///
19921/// Returns the computed value produced by [`crate::runtime::json_commands::dynamic_service_badge_color`].
19922///
19923/// # Performance
19924///
19925/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_service_badge_color`].
19926///
19927/// # Examples
19928///
19929/// ```rust,ignore
19930/// let _result = pharos_native::runtime::json_commands::dynamic_service_badge_color(todo!());
19931/// ```
19932///
19933/// # Related
19934///
19935/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19936pub fn dynamic_service_badge_color(primary_color: &str) -> &'static str {
19937    let color = primary_color.trim();
19938    if color.len() == 7
19939        && color.starts_with('#')
19940        && color[1..].bytes().all(|byte| byte.is_ascii_hexdigit())
19941    {
19942        "var(--service-primary-color)"
19943    } else {
19944        "#475569"
19945    }
19946}
19947
19948/// Initializes an incremental SHA-256 context.
19949///
19950/// # Returns
19951///
19952/// Returns the computed value produced by [`crate::runtime::json_commands::sha256_init_logic_local`].
19953///
19954/// # Performance
19955///
19956/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::sha256_init_logic_local`].
19957///
19958/// # Examples
19959///
19960/// ```rust,ignore
19961/// let _result = pharos_native::runtime::json_commands::sha256_init_logic_local();
19962/// ```
19963///
19964/// # Related
19965///
19966/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19967pub fn sha256_init_logic_local() -> Sha256 {
19968    Sha256::new()
19969}
19970
19971/// Updates an incremental SHA-256 context.
19972///
19973/// # Parameters
19974///
19975/// - `context`: Input consumed by [`crate::runtime::json_commands::sha256_update_logic_local`].
19976/// - `bytes`: Input consumed by [`crate::runtime::json_commands::sha256_update_logic_local`].
19977///
19978/// # Returns
19979///
19980/// Returns after [`crate::runtime::json_commands::sha256_update_logic_local`] applies its in-place effect.
19981///
19982/// # Examples
19983///
19984/// ```rust,ignore
19985/// let _result = pharos_native::runtime::json_commands::sha256_update_logic_local(todo!(), b"");
19986/// ```
19987///
19988/// # Related
19989///
19990/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
19991pub fn sha256_update_logic_local(context: &mut Sha256, bytes: &[u8]) {
19992    context.update(bytes);
19993}
19994
19995/// Finalizes an incremental SHA-256 context.
19996///
19997/// # Parameters
19998///
19999/// - `context`: Input consumed by [`crate::runtime::json_commands::sha256_final_logic_local`].
20000///
20001/// # Returns
20002///
20003/// Returns the computed value produced by [`crate::runtime::json_commands::sha256_final_logic_local`].
20004///
20005/// # Examples
20006///
20007/// ```rust,ignore
20008/// let _result = pharos_native::runtime::json_commands::sha256_final_logic_local(todo!());
20009/// ```
20010///
20011/// # Related
20012///
20013/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20014pub fn sha256_final_logic_local(context: Sha256) -> [u8; 32] {
20015    context.finalize().into()
20016}
20017
20018/// Computes a one-block SHA-256 digest for the transform contract.
20019///
20020/// # Parameters
20021///
20022/// - `block`: Input consumed by [`crate::runtime::json_commands::sha256_transform_logic_local`].
20023///
20024/// # Returns
20025///
20026/// Returns the computed value produced by [`crate::runtime::json_commands::sha256_transform_logic_local`].
20027///
20028/// # Examples
20029///
20030/// ```rust,ignore
20031/// let _result = pharos_native::runtime::json_commands::sha256_transform_logic_local(todo!());
20032/// ```
20033///
20034/// # Related
20035///
20036/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20037pub fn sha256_transform_logic_local(block: &[u8]) -> [u8; 32] {
20038    Sha256::digest(block).into()
20039}
20040
20041/// Rotates a 32-bit word right by a masked count.
20042///
20043/// # Parameters
20044///
20045/// - `value`: Input consumed by [`crate::runtime::json_commands::sha256_rotr_logic_local`].
20046/// - `count`: Input consumed by [`crate::runtime::json_commands::sha256_rotr_logic_local`].
20047///
20048/// # Returns
20049///
20050/// Returns the computed value produced by [`crate::runtime::json_commands::sha256_rotr_logic_local`].
20051///
20052/// # Examples
20053///
20054/// ```rust,ignore
20055/// let _result = pharos_native::runtime::json_commands::sha256_rotr_logic_local("value", 0);
20056/// ```
20057///
20058/// # Related
20059///
20060/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20061pub fn sha256_rotr_logic_local(value: u32, count: u32) -> u32 {
20062    value.rotate_right(count & 31)
20063}
20064
20065/// Returns a lowercase SHA-256 hexadecimal digest.
20066///
20067/// # Parameters
20068///
20069/// - `value`: Input consumed by [`crate::runtime::json_commands::sha256_hex`].
20070///
20071/// # Returns
20072///
20073/// Returns the computed value produced by [`crate::runtime::json_commands::sha256_hex`].
20074///
20075/// # Examples
20076///
20077/// ```rust,ignore
20078/// let _result = pharos_native::runtime::json_commands::sha256_hex("value");
20079/// ```
20080///
20081/// # Related
20082///
20083/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20084pub fn sha256_hex(value: &[u8]) -> String {
20085    pharos_runtime_core::support::sha256_hex(value)
20086}
20087
20088/// Returns the weekday abbreviation for a validated ISO date.
20089///
20090/// # Parameters
20091///
20092/// - `year`: Input consumed by [`crate::runtime::json_commands::day_abbrev_for_ymd_business_logic_local`].
20093/// - `month`: Input consumed by [`crate::runtime::json_commands::day_abbrev_for_ymd_business_logic_local`].
20094/// - `day`: Input consumed by [`crate::runtime::json_commands::day_abbrev_for_ymd_business_logic_local`].
20095///
20096/// # Returns
20097///
20098/// Returns [`Some`] when [`crate::runtime::json_commands::day_abbrev_for_ymd_business_logic_local`] can produce a value and [`None`] otherwise.
20099///
20100/// # Examples
20101///
20102/// ```rust,ignore
20103/// let _result = pharos_native::runtime::json_commands::day_abbrev_for_ymd_business_logic_local(todo!(), todo!(), todo!());
20104/// ```
20105///
20106/// # Related
20107///
20108/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20109pub fn day_abbrev_for_ymd_business_logic_local(
20110    year: i32,
20111    month: u32,
20112    day: u32,
20113) -> Option<&'static str> {
20114    let days = days_from_civil(year, month, day)?;
20115    Some(["Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"][days.rem_euclid(7) as usize])
20116}
20117
20118/// Formats a validated time range.
20119fn formatted_clock_time_business_logic_local(time_text: &str) -> String {
20120    let Some((hour_text, minute_text)) = time_text.split_once(':') else {
20121        return time_text.to_owned();
20122    };
20123    let Some(hour) = hour_text.parse::<u32>().ok() else {
20124        return time_text.to_owned();
20125    };
20126    let Some(minute) = minute_text.parse::<u32>().ok() else {
20127        return time_text.to_owned();
20128    };
20129    if hour > 23 || minute > 59 {
20130        return time_text.to_owned();
20131    }
20132    let suffix = if hour < 12 { "AM" } else { "PM" };
20133    let display_hour = match hour % 12 {
20134        0 => 12,
20135        value => value,
20136    };
20137    format!("{display_hour}:{minute:02} {suffix}")
20138}
20139
20140fn appointment_time_plus_minutes(time_text: &str, duration_minutes: i64) -> Option<String> {
20141    let (hour_text, minute_text) = time_text.split_once(':')?;
20142    let hour = hour_text.parse::<i64>().ok()?;
20143    let minute = minute_text.parse::<i64>().ok()?;
20144    if !(0..=23).contains(&hour) || !(0..=59).contains(&minute) || duration_minutes <= 0 {
20145        return None;
20146    }
20147    let total_minutes = hour
20148        .saturating_mul(60)
20149        .saturating_add(minute)
20150        .saturating_add(duration_minutes);
20151    let day_minutes = 24 * 60;
20152    let normalized_minutes = total_minutes.rem_euclid(day_minutes);
20153    Some(format!(
20154        "{:02}:{:02}",
20155        normalized_minutes / 60,
20156        normalized_minutes % 60
20157    ))
20158}
20159
20160/// Performs formatted time range business logic local.
20161///
20162/// # Parameters
20163///
20164/// - `start_time`: Input consumed by [`crate::runtime::json_commands::formatted_time_range_business_logic_local`].
20165/// - `end_time`: Input consumed by [`crate::runtime::json_commands::formatted_time_range_business_logic_local`].
20166///
20167/// # Returns
20168///
20169/// Returns the computed value produced by [`crate::runtime::json_commands::formatted_time_range_business_logic_local`].
20170///
20171/// # Examples
20172///
20173/// ```rust,ignore
20174/// let _result = pharos_native::runtime::json_commands::formatted_time_range_business_logic_local(todo!(), todo!());
20175/// ```
20176///
20177/// # Related
20178///
20179/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20180pub fn formatted_time_range_business_logic_local(start_time: &str, end_time: &str) -> String {
20181    if start_time.is_empty() {
20182        return formatted_clock_time_business_logic_local(end_time);
20183    }
20184    if end_time.is_empty() {
20185        return formatted_clock_time_business_logic_local(start_time);
20186    }
20187    format!(
20188        "{}–{}",
20189        formatted_clock_time_business_logic_local(start_time),
20190        formatted_clock_time_business_logic_local(end_time)
20191    )
20192}
20193
20194/// Performs days from civil.
20195fn days_from_civil(year: i32, month: u32, day: u32) -> Option<i64> {
20196    if !(1..=12).contains(&month)
20197        || day == 0
20198        || day > days_in_month_business_logic_local(year, month)
20199    {
20200        return None;
20201    }
20202    let y = year - i32::from(month <= 2);
20203    let era = i64::from(y).div_euclid(400);
20204    let yoe = i64::from(y).rem_euclid(400);
20205    let mp = i64::from(month) + if month > 2 { -3 } else { 9 };
20206    let doy = (153 * mp + 2) / 5 + i64::from(day) - 1;
20207    let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
20208    Some(era * 146097 + doe - 719468)
20209}
20210
20211/// Returns the number of days in a Gregorian month.
20212///
20213/// # Parameters
20214///
20215/// - `year`: Input consumed by [`crate::runtime::json_commands::days_in_month_business_logic_local`].
20216/// - `month`: Input consumed by [`crate::runtime::json_commands::days_in_month_business_logic_local`].
20217///
20218/// # Returns
20219///
20220/// Returns the computed value produced by [`crate::runtime::json_commands::days_in_month_business_logic_local`].
20221///
20222/// # Examples
20223///
20224/// ```rust,ignore
20225/// let _result = pharos_native::runtime::json_commands::days_in_month_business_logic_local(todo!(), todo!());
20226/// ```
20227///
20228/// # Related
20229///
20230/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20231pub fn days_in_month_business_logic_local(year: i32, month: u32) -> u32 {
20232    match month {
20233        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
20234        4 | 6 | 9 | 11 => 30,
20235        2 if year.rem_euclid(4) == 0
20236            && (year.rem_euclid(100) != 0 || year.rem_euclid(400) == 0) =>
20237        {
20238            29
20239        }
20240        2 => 28,
20241        _ => 0,
20242    }
20243}
20244
20245/// Finds the named month.
20246///
20247/// # Parameters
20248///
20249/// - `month`: Input consumed by [`crate::runtime::json_commands::month_name_business_logic_local`].
20250///
20251/// # Returns
20252///
20253/// Returns [`Some`] when [`crate::runtime::json_commands::month_name_business_logic_local`] can produce a value and [`None`] otherwise.
20254///
20255/// # Examples
20256///
20257/// ```rust,ignore
20258/// let _result = pharos_native::runtime::json_commands::month_name_business_logic_local(todo!());
20259/// ```
20260///
20261/// # Related
20262///
20263/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20264pub fn month_name_business_logic_local(month: u32) -> Option<&'static str> {
20265    [
20266        "",
20267        "January",
20268        "February",
20269        "March",
20270        "April",
20271        "May",
20272        "June",
20273        "July",
20274        "August",
20275        "September",
20276        "October",
20277        "November",
20278        "December",
20279    ]
20280    .get(month as usize)
20281    .copied()
20282    .filter(|value| !value.is_empty())
20283}
20284
20285/// Shifts a year/month pair by a bounded number of months.
20286///
20287/// # Parameters
20288///
20289/// - `year`: Input consumed by [`crate::runtime::json_commands::month_shift_business_logic_local`].
20290/// - `month`: Input consumed by [`crate::runtime::json_commands::month_shift_business_logic_local`].
20291/// - `shift`: Input consumed by [`crate::runtime::json_commands::month_shift_business_logic_local`].
20292/// - `u32`: Input consumed by [`crate::runtime::json_commands::month_shift_business_logic_local`].
20293///
20294/// # Returns
20295///
20296/// Returns [`Some`] when [`crate::runtime::json_commands::month_shift_business_logic_local`] can produce a value and [`None`] otherwise.
20297///
20298/// # Examples
20299///
20300/// ```rust,ignore
20301/// let _result = pharos_native::runtime::json_commands::month_shift_business_logic_local(todo!(), todo!(), todo!(), todo!());
20302/// ```
20303///
20304/// # Related
20305///
20306/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20307pub fn month_shift_business_logic_local(year: i32, month: u32, shift: i32) -> Option<(i32, u32)> {
20308    if !(1..=12).contains(&month) {
20309        return None;
20310    }
20311    let index = year
20312        .checked_mul(12)?
20313        .checked_add(month as i32 - 1)?
20314        .checked_add(shift)?;
20315    Some((index.div_euclid(12), index.rem_euclid(12) as u32 + 1))
20316}
20317
20318/// Appends an ISO date to a bounded string buffer.
20319///
20320/// # Parameters
20321///
20322/// - `output`: Input consumed by [`crate::runtime::json_commands::append_date_business_logic_local`].
20323/// - `year`: Input consumed by [`crate::runtime::json_commands::append_date_business_logic_local`].
20324/// - `month`: Input consumed by [`crate::runtime::json_commands::append_date_business_logic_local`].
20325/// - `day`: Input consumed by [`crate::runtime::json_commands::append_date_business_logic_local`].
20326///
20327/// # Returns
20328///
20329/// Returns `true` when the condition checked by [`crate::runtime::json_commands::append_date_business_logic_local`] holds and `false` otherwise.
20330///
20331/// # Examples
20332///
20333/// ```rust,ignore
20334/// let _result = pharos_native::runtime::json_commands::append_date_business_logic_local(todo!(), todo!(), todo!(), todo!());
20335/// ```
20336///
20337/// # Related
20338///
20339/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20340pub fn append_date_business_logic_local(
20341    output: &mut String,
20342    year: i32,
20343    month: u32,
20344    day: u32,
20345) -> bool {
20346    if days_from_civil(year, month, day).is_none() {
20347        return false;
20348    }
20349    let text = format!("{year:04}-{month:02}-{day:02}");
20350    if output.len().saturating_add(text.len()) > MAX_TEXT_BYTES {
20351        return false;
20352    }
20353    output.push_str(&text);
20354    true
20355}
20356
20357/// Returns the Monday-based index of a weekday name.
20358///
20359/// # Parameters
20360///
20361/// - `value`: Input consumed by [`crate::runtime::json_commands::weekday_monday_index_business_logic_local`].
20362///
20363/// # Returns
20364///
20365/// Returns [`Some`] when [`crate::runtime::json_commands::weekday_monday_index_business_logic_local`] can produce a value and [`None`] otherwise.
20366///
20367/// # Performance
20368///
20369/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::weekday_monday_index_business_logic_local`].
20370///
20371/// # Examples
20372///
20373/// ```rust,ignore
20374/// let _result = pharos_native::runtime::json_commands::weekday_monday_index_business_logic_local("value");
20375/// ```
20376///
20377/// # Related
20378///
20379/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20380pub fn weekday_monday_index_business_logic_local(value: &str) -> Option<u8> {
20381    [
20382        "monday",
20383        "tuesday",
20384        "wednesday",
20385        "thursday",
20386        "friday",
20387        "saturday",
20388        "sunday",
20389    ]
20390    .iter()
20391    .position(|name| name.eq_ignore_ascii_case(value))
20392    .map(|index| index as u8)
20393}
20394
20395/// Finds a technician row scoped to one business.
20396///
20397/// # Parameters
20398///
20399/// - `root`: Input consumed by [`crate::runtime::json_commands::find_technician_for_business_logic_local`].
20400/// - `technician_id`: Input consumed by [`crate::runtime::json_commands::find_technician_for_business_logic_local`].
20401/// - `business_id`: Input consumed by [`crate::runtime::json_commands::find_technician_for_business_logic_local`].
20402///
20403/// # Returns
20404///
20405/// Returns [`Some`] when [`crate::runtime::json_commands::find_technician_for_business_logic_local`] can produce a value and [`None`] otherwise.
20406///
20407/// # Performance
20408///
20409/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_technician_for_business_logic_local`].
20410///
20411/// # Examples
20412///
20413/// ```rust,ignore
20414/// let _result = pharos_native::runtime::json_commands::find_technician_for_business_logic_local(std::path::Path::new("."), todo!(), todo!());
20415/// ```
20416///
20417/// # Related
20418///
20419/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20420pub fn find_technician_for_business_logic_local(
20421    root: &Value,
20422    technician_id: i64,
20423    business_id: i64,
20424) -> Option<Value> {
20425    bounded_state_array(root, "technicians")
20426        .iter()
20427        .find(|row| {
20428            row.get("id").and_then(Value::as_i64) == Some(technician_id)
20429                && row.get("business_id").and_then(Value::as_i64) == Some(business_id)
20430        })
20431        .cloned()
20432}
20433
20434/// Finds a user row by identifier.
20435///
20436/// # Parameters
20437///
20438/// - `root`: Input consumed by [`crate::runtime::json_commands::find_user_by_id_business_logic_local`].
20439/// - `user_id`: Input consumed by [`crate::runtime::json_commands::find_user_by_id_business_logic_local`].
20440///
20441/// # Returns
20442///
20443/// Returns [`Some`] when [`crate::runtime::json_commands::find_user_by_id_business_logic_local`] can produce a value and [`None`] otherwise.
20444///
20445/// # Performance
20446///
20447/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_user_by_id_business_logic_local`].
20448///
20449/// # Examples
20450///
20451/// ```rust,ignore
20452/// let _result = pharos_native::runtime::json_commands::find_user_by_id_business_logic_local(std::path::Path::new("."), 1);
20453/// ```
20454///
20455/// # Related
20456///
20457/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20458pub fn find_user_by_id_business_logic_local(root: &Value, user_id: i64) -> Option<Value> {
20459    bounded_state_array(root, "users")
20460        .iter()
20461        .find(|row| row.get("id").and_then(Value::as_i64) == Some(user_id))
20462        .cloned()
20463}
20464
20465/// Returns whether a signup account type is allowed by the closed set.
20466///
20467/// # Parameters
20468///
20469/// - `account_type`: Input consumed by [`crate::runtime::json_commands::dynamic_signup_account_type_allowed`].
20470///
20471/// # Returns
20472///
20473/// Returns `true` when the condition checked by [`crate::runtime::json_commands::dynamic_signup_account_type_allowed`] holds and `false` otherwise.
20474///
20475/// # Examples
20476///
20477/// ```rust,ignore
20478/// let _result = pharos_native::runtime::json_commands::dynamic_signup_account_type_allowed(todo!());
20479/// ```
20480///
20481/// # Related
20482///
20483/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20484pub fn dynamic_signup_account_type_allowed(account_type: &str) -> bool {
20485    matches!(
20486        account_type,
20487        "personal" | "business" | "technician" | "admin"
20488    )
20489}
20490
20491/// Counts slash-separated route segments.
20492///
20493/// # Parameters
20494///
20495/// - `path`: Input consumed by [`crate::runtime::json_commands::count_segments`].
20496///
20497/// # Returns
20498///
20499/// Returns the computed value produced by [`crate::runtime::json_commands::count_segments`].
20500///
20501/// # Performance
20502///
20503/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::count_segments`].
20504///
20505/// # Examples
20506///
20507/// ```rust,ignore
20508/// let _result = pharos_native::runtime::json_commands::count_segments(std::path::Path::new("fixture.json"));
20509/// ```
20510///
20511/// # Related
20512///
20513/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20514pub fn count_segments(path: &str) -> usize {
20515    path.split('/')
20516        .filter(|segment| !segment.is_empty())
20517        .count()
20518}
20519
20520/// Returns one slash-separated segment by index.
20521///
20522/// # Parameters
20523///
20524/// - `path`: Input consumed by [`crate::runtime::json_commands::get_segment`].
20525/// - `index`: Input consumed by [`crate::runtime::json_commands::get_segment`].
20526///
20527/// # Returns
20528///
20529/// Returns [`Some`] when [`crate::runtime::json_commands::get_segment`] can produce a value and [`None`] otherwise.
20530///
20531/// # Performance
20532///
20533/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::get_segment`].
20534///
20535/// # Examples
20536///
20537/// ```rust,ignore
20538/// let _result = pharos_native::runtime::json_commands::get_segment(std::path::Path::new("fixture.json"), todo!());
20539/// ```
20540///
20541/// # Related
20542///
20543/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20544pub fn get_segment(path: &str, index: usize) -> Option<String> {
20545    path.split('/')
20546        .filter(|segment| !segment.is_empty())
20547        .nth(index)
20548        .map(ToOwned::to_owned)
20549}
20550
20551/// Returns one segment's byte length.
20552///
20553/// # Parameters
20554///
20555/// - `path`: Input consumed by [`crate::runtime::json_commands::segment_length`].
20556/// - `index`: Input consumed by [`crate::runtime::json_commands::segment_length`].
20557///
20558/// # Returns
20559///
20560/// Returns the computed value produced by [`crate::runtime::json_commands::segment_length`].
20561///
20562/// # Examples
20563///
20564/// ```rust,ignore
20565/// let _result = pharos_native::runtime::json_commands::segment_length(std::path::Path::new("fixture.json"), todo!());
20566/// ```
20567///
20568/// # Related
20569///
20570/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20571pub fn segment_length(path: &str, index: usize) -> usize {
20572    get_segment(path, index)
20573        .map(|value| value.len())
20574        .unwrap_or(0)
20575}
20576
20577/// Returns one query parameter value.
20578///
20579/// # Parameters
20580///
20581/// - `query`: Input consumed by [`crate::runtime::json_commands::dynamic_query_value`].
20582/// - `key`: Input consumed by [`crate::runtime::json_commands::dynamic_query_value`].
20583///
20584/// # Returns
20585///
20586/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_query_value`] can produce a value and [`None`] otherwise.
20587///
20588/// # Examples
20589///
20590/// ```rust,ignore
20591/// let _result = pharos_native::runtime::json_commands::dynamic_query_value("page=1", "key");
20592/// ```
20593///
20594/// # Related
20595///
20596/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20597pub fn dynamic_query_value(query: &str, key: &str) -> Option<String> {
20598    request_query_value(query, key)
20599}
20600
20601/// Returns an array-valued runtime state section.
20602///
20603/// # Parameters
20604///
20605/// - `root`: Input consumed by [`crate::runtime::json_commands::state_array_runtime_local`].
20606/// - `section`: Input consumed by [`crate::runtime::json_commands::state_array_runtime_local`].
20607///
20608/// # Returns
20609///
20610/// Returns the computed value produced by [`crate::runtime::json_commands::state_array_runtime_local`].
20611///
20612/// # Examples
20613///
20614/// ```rust,ignore
20615/// let _result = pharos_native::runtime::json_commands::state_array_runtime_local(std::path::Path::new("."), "items");
20616/// ```
20617///
20618/// # Related
20619///
20620/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20621pub fn state_array_runtime_local(root: &Value, section: &str) -> Vec<Value> {
20622    bounded_state_array(root, section).to_vec()
20623}
20624
20625/// Appends bounded runtime text.
20626///
20627/// # Parameters
20628///
20629/// - `output`: Input consumed by [`crate::runtime::json_commands::text_append_runtime_local`].
20630/// - `value`: Input consumed by [`crate::runtime::json_commands::text_append_runtime_local`].
20631///
20632/// # Returns
20633///
20634/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_append_runtime_local`] holds and `false` otherwise.
20635///
20636/// # Examples
20637///
20638/// ```rust,ignore
20639/// let _result = pharos_native::runtime::json_commands::text_append_runtime_local(todo!(), "value");
20640/// ```
20641///
20642/// # Related
20643///
20644/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20645pub fn text_append_runtime_local(output: &mut String, value: &str) -> bool {
20646    text_buffer_append_format(output, value)
20647}
20648
20649/// Escapes runtime text for HTML.
20650///
20651/// # Parameters
20652///
20653/// - `value`: Input consumed by [`crate::runtime::json_commands::html_escaped`].
20654///
20655/// # Returns
20656///
20657/// Returns the computed value produced by [`crate::runtime::json_commands::html_escaped`].
20658///
20659/// # Examples
20660///
20661/// ```rust,ignore
20662/// let _result = pharos_native::runtime::json_commands::html_escaped("value");
20663/// ```
20664///
20665/// # Related
20666///
20667/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20668pub fn html_escaped(value: &str) -> String {
20669    html_escape_text(value)
20670}
20671
20672/// Adds an escaped string to a page parameter map.
20673///
20674/// # Parameters
20675///
20676/// - `map`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_string`].
20677/// - `key`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_string`].
20678/// - `value`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_string`].
20679///
20680/// # Returns
20681///
20682/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_page_params_add_string`] holds and `false` otherwise.
20683///
20684/// # Examples
20685///
20686/// ```rust,ignore
20687/// let _result = pharos_native::runtime::json_commands::runtime_page_params_add_string(todo!(), "key", "value");
20688/// ```
20689///
20690/// # Related
20691///
20692/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20693pub fn runtime_page_params_add_string(
20694    map: &mut Map<String, Value>,
20695    key: &str,
20696    value: &str,
20697) -> bool {
20698    if key.is_empty() {
20699        return false;
20700    }
20701    map.insert(key.to_owned(), Value::String(value.to_owned()));
20702    true
20703}
20704
20705/// Adds an escaped string to a page parameter map.
20706///
20707/// # Parameters
20708///
20709/// - `map`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_escaped_string`].
20710/// - `key`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_escaped_string`].
20711/// - `value`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_add_escaped_string`].
20712///
20713/// # Returns
20714///
20715/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_page_params_add_escaped_string`] holds and `false` otherwise.
20716///
20717/// # Examples
20718///
20719/// ```rust,ignore
20720/// let _result = pharos_native::runtime::json_commands::runtime_page_params_add_escaped_string(todo!(), "key", "value");
20721/// ```
20722///
20723/// # Related
20724///
20725/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20726pub fn runtime_page_params_add_escaped_string(
20727    map: &mut Map<String, Value>,
20728    key: &str,
20729    value: &str,
20730) -> bool {
20731    runtime_page_params_add_string(map, key, &html_escape_text(value))
20732}
20733
20734/// Serializes a page parameter map.
20735///
20736/// # Parameters
20737///
20738/// - `map`: Input consumed by [`crate::runtime::json_commands::runtime_page_params_write`].
20739///
20740/// # Returns
20741///
20742/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_page_params_write`] can produce a value and [`None`] otherwise.
20743///
20744/// # Examples
20745///
20746/// ```rust,ignore
20747/// let _result = pharos_native::runtime::json_commands::runtime_page_params_write(todo!());
20748/// ```
20749///
20750/// # Related
20751///
20752/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20753pub fn runtime_page_params_write(map: &Map<String, Value>) -> Option<String> {
20754    compact(&Value::Object(map.clone()))
20755}
20756
20757/// Returns a validated management path segment.
20758///
20759/// # Parameters
20760///
20761/// - `value`: Input consumed by [`crate::runtime::json_commands::runtime_manage_path_segment`].
20762///
20763/// # Returns
20764///
20765/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_manage_path_segment`] can produce a value and [`None`] otherwise.
20766///
20767/// # Performance
20768///
20769/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::runtime_manage_path_segment`].
20770///
20771/// # Examples
20772///
20773/// ```rust,ignore
20774/// let _result = pharos_native::runtime::json_commands::runtime_manage_path_segment("value");
20775/// ```
20776///
20777/// # Related
20778///
20779/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20780pub fn runtime_manage_path_segment(value: &str) -> Option<String> {
20781    (!value.is_empty()
20782        && value.len() <= 128
20783        && value
20784            .bytes()
20785            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_')))
20786    .then(|| value.to_owned())
20787}
20788
20789/// Ensures a runtime text buffer has bounded capacity.
20790///
20791/// # Parameters
20792///
20793/// - `output`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_reserve`].
20794/// - `additional`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_reserve`].
20795///
20796/// # Returns
20797///
20798/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_text_buffer_reserve`] holds and `false` otherwise.
20799///
20800/// # Examples
20801///
20802/// ```rust,ignore
20803/// let _result = pharos_native::runtime::json_commands::runtime_text_buffer_reserve(todo!(), todo!());
20804/// ```
20805///
20806/// # Related
20807///
20808/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20809pub fn runtime_text_buffer_reserve(output: &mut String, additional: usize) -> bool {
20810    output
20811        .len()
20812        .checked_add(additional)
20813        .is_some_and(|length| length <= MAX_TEXT_BYTES)
20814        && output.try_reserve(additional).is_ok()
20815}
20816
20817/// Checks whether a UI attribute name is safe.
20818///
20819/// # Parameters
20820///
20821/// - `name`: Input consumed by [`crate::runtime::json_commands::runtime_ui_attribute_is_valid`].
20822///
20823/// # Returns
20824///
20825/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_ui_attribute_is_valid`] holds and `false` otherwise.
20826///
20827/// # Performance
20828///
20829/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::runtime_ui_attribute_is_valid`].
20830///
20831/// # Examples
20832///
20833/// ```rust,ignore
20834/// let _result = pharos_native::runtime::json_commands::runtime_ui_attribute_is_valid("name");
20835/// ```
20836///
20837/// # Related
20838///
20839/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20840pub fn runtime_ui_attribute_is_valid(name: &str) -> bool {
20841    !name.is_empty()
20842        && name
20843            .bytes()
20844            .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_')
20845}
20846
20847/// Compares two strings exactly.
20848///
20849/// # Parameters
20850///
20851/// - `left`: Input consumed by [`crate::runtime::json_commands::streq`].
20852/// - `right`: Input consumed by [`crate::runtime::json_commands::streq`].
20853///
20854/// # Returns
20855///
20856/// Returns `true` when the condition checked by [`crate::runtime::json_commands::streq`] holds and `false` otherwise.
20857///
20858/// # Examples
20859///
20860/// ```rust,ignore
20861/// let _result = pharos_native::runtime::json_commands::streq(todo!(), todo!());
20862/// ```
20863///
20864/// # Related
20865///
20866/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20867pub fn streq(left: &str, right: &str) -> bool {
20868    left == right
20869}
20870
20871/// Appends formatted text to a runtime buffer.
20872///
20873/// # Parameters
20874///
20875/// - `output`: Input consumed by [`crate::runtime::json_commands::text_append_format_runtime_local`].
20876/// - `value`: Input consumed by [`crate::runtime::json_commands::text_append_format_runtime_local`].
20877///
20878/// # Returns
20879///
20880/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_append_format_runtime_local`] holds and `false` otherwise.
20881///
20882/// # Examples
20883///
20884/// ```rust,ignore
20885/// let _result = pharos_native::runtime::json_commands::text_append_format_runtime_local(todo!(), "value");
20886/// ```
20887///
20888/// # Related
20889///
20890/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20891pub fn text_append_format_runtime_local(output: &mut String, value: &str) -> bool {
20892    text_buffer_append_format(output, value)
20893}
20894
20895/// Normalizes an email body to CRLF line endings.
20896///
20897/// # Parameters
20898///
20899/// - `value`: Input consumed by [`crate::runtime::json_commands::email_body_crlf_dup`].
20900///
20901/// # Returns
20902///
20903/// Returns the computed value produced by [`crate::runtime::json_commands::email_body_crlf_dup`].
20904///
20905/// # Examples
20906///
20907/// ```rust,ignore
20908/// let _result = pharos_native::runtime::json_commands::email_body_crlf_dup("value");
20909/// ```
20910///
20911/// # Related
20912///
20913/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20914pub fn email_body_crlf_dup(value: &str) -> String {
20915    value
20916        .replace("\r\n", "\n")
20917        .replace('\r', "\n")
20918        .replace('\n', "\r\n")
20919}
20920
20921/// Returns a stable RFC-style date header value.
20922///
20923/// # Returns
20924///
20925/// Returns the computed value produced by [`crate::runtime::json_commands::email_date_header_dup`].
20926///
20927/// # Examples
20928///
20929/// ```rust,ignore
20930/// let _result = pharos_native::runtime::json_commands::email_date_header_dup();
20931/// ```
20932///
20933/// # Related
20934///
20935/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20936pub fn email_date_header_dup() -> String {
20937    format!(
20938        "Date: {}",
20939        super::dynamic::now_unix_epoch_text_logic_local()
20940    )
20941}
20942
20943/// Resolves one email configuration value from app and runtime configuration.
20944///
20945/// # Parameters
20946///
20947/// - `app_root`: Input consumed by [`crate::runtime::json_commands::email_effective_value`].
20948/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::email_effective_value`].
20949/// - `prefix`: Input consumed by [`crate::runtime::json_commands::email_effective_value`].
20950/// - `suffix`: Input consumed by [`crate::runtime::json_commands::email_effective_value`].
20951///
20952/// # Returns
20953///
20954/// Returns [`Some`] when [`crate::runtime::json_commands::email_effective_value`] can produce a value and [`None`] otherwise.
20955///
20956/// # Examples
20957///
20958/// ```rust,ignore
20959/// let _result = pharos_native::runtime::json_commands::email_effective_value(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!());
20960/// ```
20961///
20962/// # Related
20963///
20964/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20965pub fn email_effective_value(
20966    app_root: &Path,
20967    runtime_conf_path: Option<&Path>,
20968    prefix: &str,
20969    suffix: &str,
20970) -> Option<String> {
20971    let key = if prefix.is_empty() {
20972        suffix.to_owned()
20973    } else {
20974        format!("{prefix}_{suffix}")
20975    };
20976    config::dynamic_config_effective_value(app_root, runtime_conf_path, &key)
20977}
20978
20979/// Looks up one bounded email template variable.
20980///
20981/// # Parameters
20982///
20983/// - `vars`: Input consumed by [`crate::runtime::json_commands::email_template_lookup_var`].
20984/// - `key`: Input consumed by [`crate::runtime::json_commands::email_template_lookup_var`].
20985///
20986/// # Returns
20987///
20988/// Returns [`Some`] when [`crate::runtime::json_commands::email_template_lookup_var`] can produce a value and [`None`] otherwise.
20989///
20990/// # Examples
20991///
20992/// ```rust,ignore
20993/// let _result = pharos_native::runtime::json_commands::email_template_lookup_var(todo!(), "key");
20994/// ```
20995///
20996/// # Related
20997///
20998/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
20999pub fn email_template_lookup_var(vars: &Value, key: &str) -> Option<String> {
21000    vars.get(key)
21001        .map(value_to_text)
21002        .filter(|value| value.len() <= MAX_TEXT_BYTES)
21003}
21004
21005/// Appends one YAML block line after removing the declared indentation.
21006///
21007/// # Parameters
21008///
21009/// - `buffer`: Input consumed by [`crate::runtime::json_commands::email_yaml_append_block_line`].
21010/// - `line`: Input consumed by [`crate::runtime::json_commands::email_yaml_append_block_line`].
21011/// - `indent_to_strip`: Input consumed by [`crate::runtime::json_commands::email_yaml_append_block_line`].
21012///
21013/// # Returns
21014///
21015/// Returns `true` when the condition checked by [`crate::runtime::json_commands::email_yaml_append_block_line`] holds and `false` otherwise.
21016///
21017/// # Examples
21018///
21019/// ```rust,ignore
21020/// let _result = pharos_native::runtime::json_commands::email_yaml_append_block_line(&mut [], todo!(), todo!());
21021/// ```
21022///
21023/// # Related
21024///
21025/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21026pub fn email_yaml_append_block_line(
21027    buffer: &mut String,
21028    line: &str,
21029    indent_to_strip: usize,
21030) -> bool {
21031    let stripped = line.get(line.len().min(indent_to_strip)..).unwrap_or("");
21032    if buffer.len().saturating_add(stripped.len() + 2) > MAX_TEXT_BYTES {
21033        return false;
21034    }
21035    buffer.push_str(stripped);
21036    buffer.push('\n');
21037    true
21038}
21039
21040/// Stores a completed YAML block in a mutable template object.
21041///
21042/// # Parameters
21043///
21044/// - `parsed`: Input consumed by [`crate::runtime::json_commands::email_yaml_finalize_block`].
21045/// - `key`: Input consumed by [`crate::runtime::json_commands::email_yaml_finalize_block`].
21046/// - `buffer`: Input consumed by [`crate::runtime::json_commands::email_yaml_finalize_block`].
21047///
21048/// # Returns
21049///
21050/// Returns `true` when the condition checked by [`crate::runtime::json_commands::email_yaml_finalize_block`] holds and `false` otherwise.
21051///
21052/// # Examples
21053///
21054/// ```rust,ignore
21055/// let _result = pharos_native::runtime::json_commands::email_yaml_finalize_block(todo!(), "key", &mut []);
21056/// ```
21057///
21058/// # Related
21059///
21060/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21061pub fn email_yaml_finalize_block(parsed: &mut Map<String, Value>, key: &str, buffer: &str) -> bool {
21062    if key.is_empty() {
21063        return false;
21064    }
21065    parsed.insert(
21066        key.to_owned(),
21067        Value::String(buffer.trim_end_matches('\n').to_owned()),
21068    );
21069    true
21070}
21071
21072/// Stores a scalar YAML field in a mutable template object.
21073///
21074/// # Parameters
21075///
21076/// - `parsed`: Input consumed by [`crate::runtime::json_commands::email_yaml_store_field`].
21077/// - `key`: Input consumed by [`crate::runtime::json_commands::email_yaml_store_field`].
21078/// - `value`: Input consumed by [`crate::runtime::json_commands::email_yaml_store_field`].
21079///
21080/// # Returns
21081///
21082/// Returns `true` when the condition checked by [`crate::runtime::json_commands::email_yaml_store_field`] holds and `false` otherwise.
21083///
21084/// # Examples
21085///
21086/// ```rust,ignore
21087/// let _result = pharos_native::runtime::json_commands::email_yaml_store_field(todo!(), "key", "value");
21088/// ```
21089///
21090/// # Related
21091///
21092/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21093pub fn email_yaml_store_field(parsed: &mut Map<String, Value>, key: &str, value: &str) -> bool {
21094    if key.is_empty() || value.len() > MAX_TEXT_BYTES {
21095        return false;
21096    }
21097    parsed.insert(
21098        key.to_owned(),
21099        Value::String(value.trim().trim_matches(['"', '\'']).to_owned()),
21100    );
21101    true
21102}
21103
21104/// Clears a parsed email YAML template.
21105///
21106/// # Parameters
21107///
21108/// - `parsed`: Input consumed by [`crate::runtime::json_commands::email_yaml_template_clear`].
21109///
21110/// # Returns
21111///
21112/// Returns after [`crate::runtime::json_commands::email_yaml_template_clear`] applies its in-place effect.
21113///
21114/// # Examples
21115///
21116/// ```rust,ignore
21117/// let _result = pharos_native::runtime::json_commands::email_yaml_template_clear(todo!());
21118/// ```
21119///
21120/// # Related
21121///
21122/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21123pub fn email_yaml_template_clear(parsed: &mut Map<String, Value>) {
21124    parsed.clear();
21125}
21126
21127/// Resolves a namespaced email configuration key.
21128///
21129/// # Parameters
21130///
21131/// - `prefix`: Input consumed by [`crate::runtime::json_commands::email_config_key_dup`].
21132/// - `suffix`: Input consumed by [`crate::runtime::json_commands::email_config_key_dup`].
21133///
21134/// # Returns
21135///
21136/// Returns [`Some`] when [`crate::runtime::json_commands::email_config_key_dup`] can produce a value and [`None`] otherwise.
21137///
21138/// # Examples
21139///
21140/// ```rust,ignore
21141/// let _result = pharos_native::runtime::json_commands::email_config_key_dup(todo!(), todo!());
21142/// ```
21143///
21144/// # Related
21145///
21146/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21147pub fn email_config_key_dup(prefix: &str, suffix: &str) -> Option<String> {
21148    (!suffix.is_empty()).then(|| {
21149        if prefix.is_empty() {
21150            suffix.to_owned()
21151        } else {
21152            format!("{prefix}_{suffix}")
21153        }
21154    })
21155}
21156
21157/// Rejects CRLF header injection in email field values.
21158///
21159/// # Parameters
21160///
21161/// - `value`: Input consumed by [`crate::runtime::json_commands::email_has_header_breaks`].
21162///
21163/// # Returns
21164///
21165/// Returns `true` when the condition checked by [`crate::runtime::json_commands::email_has_header_breaks`] holds and `false` otherwise.
21166///
21167/// # Examples
21168///
21169/// ```rust,ignore
21170/// let _result = pharos_native::runtime::json_commands::email_has_header_breaks("value");
21171/// ```
21172///
21173/// # Related
21174///
21175/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21176pub fn email_has_header_breaks(value: &str) -> bool {
21177    value.contains('\r') || value.contains('\n')
21178}
21179
21180/// Removes one layer of matching email-template quotes.
21181///
21182/// # Parameters
21183///
21184/// - `value`: Input consumed by [`crate::runtime::json_commands::email_template_unquote_dup`].
21185///
21186/// # Returns
21187///
21188/// Returns the computed value produced by [`crate::runtime::json_commands::email_template_unquote_dup`].
21189///
21190/// # Examples
21191///
21192/// ```rust,ignore
21193/// let _result = pharos_native::runtime::json_commands::email_template_unquote_dup("value");
21194/// ```
21195///
21196/// # Related
21197///
21198/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21199pub fn email_template_unquote_dup(value: &str) -> String {
21200    let value = value.trim();
21201    if value.len() >= 2
21202        && ((value.starts_with('"') && value.ends_with('"'))
21203            || (value.starts_with('\'') && value.ends_with('\'')))
21204    {
21205        value[1..value.len() - 1].to_owned()
21206    } else {
21207        value.to_owned()
21208    }
21209}
21210
21211/// Releases a parsed URL value by normal Rust ownership rules.
21212///
21213/// # Parameters
21214///
21215/// - `value`: Input consumed by [`crate::runtime::json_commands::free_parsed_http_url_logic_local`].
21216///
21217/// # Returns
21218///
21219/// Returns after [`crate::runtime::json_commands::free_parsed_http_url_logic_local`] applies its in-place effect.
21220///
21221/// # Examples
21222///
21223/// ```rust,ignore
21224/// let _result = pharos_native::runtime::json_commands::free_parsed_http_url_logic_local("value");
21225/// ```
21226///
21227/// # Related
21228///
21229/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21230pub fn free_parsed_http_url_logic_local(value: Option<(String, String, Option<u16>)>) {
21231    drop(value);
21232}
21233
21234/// Renders an app-owned shared fragment from a parameter document.
21235///
21236/// # Parameters
21237///
21238/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_from_doc`].
21239/// - `relative_path`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_from_doc`].
21240/// - `params`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_from_doc`].
21241///
21242/// # Returns
21243///
21244/// Returns [`Some`] when [`crate::runtime::json_commands::render_shared_asset_fragment_from_doc`] can produce a value and [`None`] otherwise.
21245///
21246/// # Examples
21247///
21248/// ```rust,ignore
21249/// let _result = pharos_native::runtime::json_commands::render_shared_asset_fragment_from_doc(std::path::Path::new("apps/dev_docs"), "page", todo!());
21250/// ```
21251///
21252/// # Related
21253///
21254/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21255pub fn render_shared_asset_fragment_from_doc(
21256    app_root: &Path,
21257    relative_path: &str,
21258    params: &Value,
21259) -> Option<String> {
21260    generated::render_generated_admin_fragment_from_value_runtime(
21261        app_root,
21262        relative_path,
21263        params.as_object()?,
21264    )
21265}
21266
21267/// Builds profile page parameters from a state root.
21268///
21269/// # Parameters
21270///
21271/// - `root`: Input consumed by [`crate::runtime::json_commands::profile_render_page_params_json`].
21272/// - `user_id`: Input consumed by [`crate::runtime::json_commands::profile_render_page_params_json`].
21273/// - `app_root`: Input consumed by [`crate::runtime::json_commands::profile_render_page_params_json`].
21274///
21275/// # Returns
21276///
21277/// Returns [`Some`] when [`crate::runtime::json_commands::profile_render_page_params_json`] can produce a value and [`None`] otherwise.
21278///
21279/// # Examples
21280///
21281/// ```rust,ignore
21282/// let _result = pharos_native::runtime::json_commands::profile_render_page_params_json(std::path::Path::new("."), 1, std::path::Path::new("apps/dev_docs"));
21283/// ```
21284///
21285/// # Related
21286///
21287/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21288pub fn profile_render_page_params_json(
21289    root: &Value,
21290    user_id: i64,
21291    app_root: &Path,
21292) -> Option<String> {
21293    dynamic_profile_page_params_json(root, user_id, app_root)
21294}
21295
21296/// Tests whether a path ends with a validated suffix.
21297///
21298/// # Parameters
21299///
21300/// - `path`: Input consumed by [`crate::runtime::json_commands::runtime_path_has_suffix`].
21301/// - `suffix`: Input consumed by [`crate::runtime::json_commands::runtime_path_has_suffix`].
21302///
21303/// # Returns
21304///
21305/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_path_has_suffix`] holds and `false` otherwise.
21306///
21307/// # Examples
21308///
21309/// ```rust,ignore
21310/// let _result = pharos_native::runtime::json_commands::runtime_path_has_suffix(std::path::Path::new("fixture.json"), todo!());
21311/// ```
21312///
21313/// # Related
21314///
21315/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21316pub fn runtime_path_has_suffix(path: &Path, suffix: &str) -> bool {
21317    !suffix.is_empty() && path.to_string_lossy().ends_with(suffix)
21318}
21319
21320/// Renders availability rows from persisted business state.
21321///
21322/// # Parameters
21323///
21324/// - `root`: Input consumed by [`crate::runtime::json_commands::dynamic_build_business_admin_availability_rows_html`].
21325/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_build_business_admin_availability_rows_html`].
21326/// - `app_root`: Input consumed by [`crate::runtime::json_commands::dynamic_build_business_admin_availability_rows_html`].
21327///
21328/// # Returns
21329///
21330/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_build_business_admin_availability_rows_html`] can produce a value and [`None`] otherwise.
21331///
21332/// # Examples
21333///
21334/// ```rust,ignore
21335/// let _result = pharos_native::runtime::json_commands::dynamic_build_business_admin_availability_rows_html(std::path::Path::new("."), "demo", std::path::Path::new("apps/dev_docs"));
21336/// ```
21337///
21338/// # Related
21339///
21340/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21341pub fn dynamic_build_business_admin_availability_rows_html(
21342    root: &Value,
21343    business_slug: &str,
21344    app_root: &Path,
21345) -> Option<String> {
21346    dynamic_render_business_admin_availability_rows_html(root, business_slug, app_root)
21347}
21348
21349/// Finds a Google Calendar connection scoped to a business.
21350///
21351/// # Parameters
21352///
21353/// - `root`: Input consumed by [`crate::runtime::json_commands::state_find_google_calendar_connection_for_business_logic_local`].
21354/// - `business_id`: Input consumed by [`crate::runtime::json_commands::state_find_google_calendar_connection_for_business_logic_local`].
21355///
21356/// # Returns
21357///
21358/// Returns [`Some`] when [`crate::runtime::json_commands::state_find_google_calendar_connection_for_business_logic_local`] can produce a value and [`None`] otherwise.
21359///
21360/// # Performance
21361///
21362/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::state_find_google_calendar_connection_for_business_logic_local`].
21363///
21364/// # Examples
21365///
21366/// ```rust,ignore
21367/// let _result = pharos_native::runtime::json_commands::state_find_google_calendar_connection_for_business_logic_local(std::path::Path::new("."), todo!());
21368/// ```
21369///
21370/// # Related
21371///
21372/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21373pub fn state_find_google_calendar_connection_for_business_logic_local(
21374    root: &Value,
21375    business_id: i64,
21376) -> Option<Value> {
21377    bounded_state_array(root, "calendar_connections")
21378        .iter()
21379        .find(|row| {
21380            row.get("business_id").and_then(Value::as_i64) == Some(business_id)
21381                && row
21382                    .get("provider")
21383                    .and_then(Value::as_str)
21384                    .is_some_and(|value| value.eq_ignore_ascii_case("google"))
21385        })
21386        .cloned()
21387}
21388
21389/// Finds one payment provider account row for a business and provider.
21390pub fn state_find_payment_provider_account_for_business_logic_local(
21391    root: &Value,
21392    business_id: i64,
21393    provider: &str,
21394) -> Option<Value> {
21395    if provider.is_empty() {
21396        return None;
21397    }
21398    bounded_state_array(root, "payment_provider_accounts")
21399        .iter()
21400        .find(|row| {
21401            row.get("owner_resource_type")
21402                .and_then(Value::as_str)
21403                .unwrap_or("business")
21404                == "business"
21405                && row.get("owner_resource_id").and_then(Value::as_i64) == Some(business_id)
21406                && row
21407                    .get("provider_id")
21408                    .or_else(|| row.get("provider"))
21409                    .and_then(Value::as_str)
21410                    .is_some_and(|value| value.eq_ignore_ascii_case(provider))
21411        })
21412        .cloned()
21413}
21414
21415fn payment_provider_display_label(provider_id: &str) -> String {
21416    if provider_id.eq_ignore_ascii_case("stripe") {
21417        return "Stripe".to_owned();
21418    }
21419    let normalized = provider_id.replace(['_', '-'], " ");
21420    let mut chars = normalized.chars();
21421    let Some(first) = chars.next() else {
21422        return "Provider".to_owned();
21423    };
21424    format!("{}{}", first.to_uppercase(), chars.as_str())
21425}
21426
21427fn business_payment_provider_ui_config(app_root: &Path) -> (String, String) {
21428    let manifest = read_json_or_yaml_file(&app_root.join("pharos.app.json"))
21429        .or_else(|| read_json_or_yaml_file(&app_root.join("pharos.app.yml")));
21430    let provider_id = manifest
21431        .as_ref()
21432        .and_then(|root| root.get("payments"))
21433        .and_then(|payments| payments.get("provider_management"))
21434        .and_then(|management| management.get("supported_providers"))
21435        .and_then(Value::as_array)
21436        .into_iter()
21437        .flatten()
21438        .find_map(|provider| {
21439            provider
21440                .get("provider")
21441                .and_then(Value::as_str)
21442                .or_else(|| provider.as_str())
21443        })
21444        .filter(|provider| {
21445            !provider.is_empty()
21446                && provider.len() <= 64
21447                && provider
21448                    .bytes()
21449                    .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-'))
21450        })
21451        .unwrap_or("stripe")
21452        .to_owned();
21453    let label = payment_provider_display_label(&provider_id);
21454    (provider_id, label)
21455}
21456
21457fn business_payment_provider_paths(
21458    business_slug: &str,
21459    payment_provider_id: &str,
21460) -> (String, String, String) {
21461    (
21462        format!("/businesses/{business_slug}/payment-providers/{payment_provider_id}/connect/"),
21463        format!("/businesses/{business_slug}/payment-providers/{payment_provider_id}/refresh/"),
21464        format!("/businesses/{business_slug}/payment-providers/{payment_provider_id}/disconnect/"),
21465    )
21466}
21467
21468fn business_payment_provider_status(
21469    root: &Value,
21470    business_id: i64,
21471    payment_provider_id: &str,
21472    payment_provider_label: &str,
21473) -> (String, String) {
21474    let payment_provider_account = state_find_payment_provider_account_for_business_logic_local(
21475        root,
21476        business_id,
21477        payment_provider_id,
21478    );
21479    let status_label = payment_provider_account
21480        .as_ref()
21481        .and_then(|row| row.get("connection_state").or_else(|| row.get("status")))
21482        .and_then(Value::as_str)
21483        .map(|status| match status {
21484            "connected" => "Connected",
21485            "connect_requested" | "redirect_pending" | "callback_received" => "Onboarding started",
21486            "verification_pending" => "Verification pending",
21487            "restricted" => "Connected with restrictions",
21488            "revoked_externally" => "Revoked externally",
21489            "failed" => "Failed",
21490            _ => "Disconnected",
21491        })
21492        .unwrap_or("Disconnected")
21493        .to_owned();
21494    let status_detail = payment_provider_account
21495        .as_ref()
21496        .and_then(|row| {
21497            row.get("status_reason_detail")
21498                .or_else(|| row.get("last_error_message"))
21499        })
21500        .and_then(Value::as_str)
21501        .filter(|value| !value.is_empty())
21502        .map(ToOwned::to_owned)
21503        .unwrap_or_else(|| match status_label.as_str() {
21504            "Connected" => format!(
21505                "{payment_provider_label} account linked and available for business payments."
21506            ),
21507            "Onboarding started" => format!(
21508                "{payment_provider_label} onboarding is in progress and waiting for callback completion."
21509            ),
21510            "Verification pending" => {
21511                format!(
21512                    "{payment_provider_label} returned successfully, but the account still needs authoritative capability verification."
21513                )
21514            }
21515            "Connected with restrictions" => {
21516                format!(
21517                    "{payment_provider_label} account linked but still restricted for one or more capabilities."
21518                )
21519            }
21520            "Revoked externally" => {
21521                format!(
21522                    "The provider reported that the {payment_provider_label} connection is no longer valid."
21523                )
21524            }
21525            "Failed" => format!(
21526                "The last {payment_provider_label} operation failed. Refresh or reconnect to retry."
21527            ),
21528            _ => "No business payment provider is connected yet.".to_owned(),
21529        });
21530    (status_label, status_detail)
21531}
21532
21533fn payment_provider_action_button_html(
21534    app_root: &Path,
21535    id: &str,
21536    label: &str,
21537    class_name: &str,
21538) -> Option<String> {
21539    render_fragment_with_params(
21540        app_root,
21541        "templates/shared/fragments/ui_button.html",
21542        Map::from_iter([
21543            ("id".to_owned(), Value::String(id.to_owned())),
21544            ("button_type".to_owned(), Value::String("submit".to_owned())),
21545            (
21546                "class_name".to_owned(),
21547                Value::String(class_name.to_owned()),
21548            ),
21549            ("attributes_html".to_owned(), Value::String(String::new())),
21550            ("content_html".to_owned(), Value::String(label.to_owned())),
21551        ]),
21552    )
21553}
21554
21555/// Builds payment provider setup page parameters for one business.
21556///
21557/// # Parameters
21558///
21559/// - `root`: Loaded UCAL dynamic runtime state.
21560/// - `business_slug`: Route-owned business slug.
21561/// - `app_root`: UCAL app artifact root used for declared fragments.
21562///
21563/// # Returns
21564///
21565/// Returns JSON template parameters when the business and declared fragments can
21566/// be resolved. The values intentionally include only paths, labels, and
21567/// rendered button fragments; provider secrets and OAuth credentials are never
21568/// included in the page payload.
21569pub fn dynamic_payment_provider_setup_page_params_from_root_json(
21570    root: &Value,
21571    business_slug: &str,
21572    app_root: &Path,
21573) -> Option<String> {
21574    let business = bounded_state_array(root, "businesses")
21575        .iter()
21576        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
21577    let business_id = business.get("id").and_then(Value::as_i64)?;
21578    let business_name = business.get("name").map(value_to_text).unwrap_or_default();
21579    let (payment_provider_id, payment_provider_label) =
21580        business_payment_provider_ui_config(app_root);
21581    let (payment_provider_status_label, payment_provider_status_detail) =
21582        business_payment_provider_status(
21583            root,
21584            business_id,
21585            &payment_provider_id,
21586            &payment_provider_label,
21587        );
21588    let (
21589        payment_provider_connect_path,
21590        payment_provider_refresh_path,
21591        payment_provider_disconnect_path,
21592    ) = business_payment_provider_paths(business_slug, &payment_provider_id);
21593    let mut params = Map::from_iter([
21594        ("business_name".to_owned(), Value::String(business_name)),
21595        (
21596            "business_admin_path".to_owned(),
21597            Value::String(format!("/businesses/{business_slug}/")),
21598        ),
21599        (
21600            "payment_provider_label".to_owned(),
21601            Value::String(payment_provider_label.clone()),
21602        ),
21603        (
21604            "payment_provider_status_label".to_owned(),
21605            Value::String(payment_provider_status_label),
21606        ),
21607        (
21608            "payment_provider_status_detail".to_owned(),
21609            Value::String(payment_provider_status_detail),
21610        ),
21611        (
21612            "payment_provider_connect_path".to_owned(),
21613            Value::String(payment_provider_connect_path),
21614        ),
21615        (
21616            "payment_provider_refresh_path".to_owned(),
21617            Value::String(payment_provider_refresh_path),
21618        ),
21619        (
21620            "payment_provider_disconnect_path".to_owned(),
21621            Value::String(payment_provider_disconnect_path),
21622        ),
21623        (
21624            "payment_provider_connect_button_ui_html".to_owned(),
21625            Value::String(payment_provider_action_button_html(
21626                app_root,
21627                "payment_provider_connect_button",
21628                &format!("Connect {payment_provider_label}"),
21629                "btn btn-primary",
21630            )?),
21631        ),
21632        (
21633            "payment_provider_refresh_button_ui_html".to_owned(),
21634            Value::String(payment_provider_action_button_html(
21635                app_root,
21636                "payment_provider_refresh_button",
21637                "Refresh status",
21638                "btn btn-secondary",
21639            )?),
21640        ),
21641        (
21642            "payment_provider_disconnect_button_ui_html".to_owned(),
21643            Value::String(payment_provider_action_button_html(
21644                app_root,
21645                "payment_provider_disconnect_button",
21646                "Disconnect",
21647                "btn btn-danger",
21648            )?),
21649        ),
21650    ]);
21651    for (key, value) in super::payment_provider::payment_provider_template_params(
21652        root,
21653        app_root,
21654        business_slug,
21655        &payment_provider_id,
21656    ) {
21657        params.insert(key, value);
21658    }
21659    for key in [
21660        "owner_payment_provider_status_label",
21661        "owner_payment_provider_status_icon",
21662        "owner_payment_provider_mode_demo_label",
21663        "owner_payment_provider_mode_live_label",
21664        "owner_payment_provider_credentials_state_label",
21665        "owner_payment_provider_setup_eyebrow",
21666        "owner_payment_provider_setup_headline",
21667        "owner_payment_provider_setup_body",
21668        "owner_payment_provider_credentials_headline",
21669        "owner_payment_provider_credentials_body",
21670        "owner_payment_provider_client_id_label",
21671        "owner_payment_provider_client_id_placeholder",
21672        "owner_payment_provider_client_secret_label",
21673        "owner_payment_provider_client_secret_placeholder",
21674        "owner_payment_provider_save_credentials_label",
21675        "owner_payment_provider_delete_credentials_label",
21676        "owner_payment_provider_connect_label",
21677        "owner_payment_provider_refresh_label",
21678        "owner_payment_provider_back_label",
21679    ] {
21680        if let Some(value) = super::payment_provider::payment_provider_copy_value(app_root, key) {
21681            params.insert(key.to_owned(), Value::String(value));
21682        }
21683    }
21684    params.insert(
21685        "owner_payment_provider_action_href".to_owned(),
21686        Value::String(format!(
21687            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/test/"
21688        )),
21689    );
21690    params.insert(
21691        "owner_payment_provider_refresh_href".to_owned(),
21692        Value::String(format!(
21693            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/refresh/"
21694        )),
21695    );
21696    params.insert(
21697        "owner_payment_provider_credentials_href".to_owned(),
21698        Value::String(format!(
21699            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/"
21700        )),
21701    );
21702    params.insert(
21703        "owner_payment_provider_credentials_delete_href".to_owned(),
21704        Value::String(format!(
21705            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/delete/"
21706        )),
21707    );
21708    params.insert(
21709        "owner_payment_provider_mode_href".to_owned(),
21710        Value::String(format!(
21711            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/mode/"
21712        )),
21713    );
21714    params.insert(
21715        "payment_provider_feedback_message".to_owned(),
21716        Value::String(String::new()),
21717    );
21718    compact(&Value::Object(params))
21719}
21720
21721pub fn dynamic_business_edit_external_integrations_html(
21722    root: &Value,
21723    business_slug: &str,
21724    app_root: &Path,
21725) -> Option<String> {
21726    let business = bounded_state_array(root, "businesses")
21727        .iter()
21728        .find(|row| row.get("slug").and_then(Value::as_str) == Some(business_slug))?;
21729    let business_id = business.get("id").and_then(Value::as_i64)?;
21730    let (payment_provider_id, _payment_provider_label) =
21731        business_payment_provider_ui_config(app_root);
21732    let connection_status =
21733        if state_find_google_calendar_connection_for_business_logic_local(root, business_id)
21734            .is_some()
21735        {
21736            "Connected"
21737        } else {
21738            "Disconnected"
21739        };
21740    let mut params = Map::from_iter([
21741        (
21742            "connection_status".to_owned(),
21743            Value::String(connection_status.to_owned()),
21744        ),
21745        (
21746            "business_admin_google_mode_input_ui_html".to_owned(),
21747            Value::String(render_hidden_input_fragment(
21748                app_root,
21749                "business_edit_google_mode_input",
21750                "mode",
21751                "business",
21752            )?),
21753        ),
21754        (
21755            "business_admin_google_slug_input_ui_html".to_owned(),
21756            Value::String(render_hidden_input_fragment(
21757                app_root,
21758                "business_edit_google_slug_input",
21759                "business_slug",
21760                business_slug,
21761            )?),
21762        ),
21763        (
21764            "business_admin_google_next_input_ui_html".to_owned(),
21765            Value::String(render_hidden_input_fragment(
21766                app_root,
21767                "business_edit_google_next_input",
21768                "next",
21769                &format!("/businesses/{business_slug}/edit/"),
21770            )?),
21771        ),
21772        (
21773            "payment_provider_feedback_message".to_owned(),
21774            Value::String(String::new()),
21775        ),
21776    ]);
21777    for (key, value) in super::payment_provider::payment_provider_template_params(
21778        root,
21779        app_root,
21780        business_slug,
21781        &payment_provider_id,
21782    ) {
21783        params.insert(key, value);
21784    }
21785    for key in [
21786        "owner_payment_provider_status_label",
21787        "owner_payment_provider_status_icon",
21788        "owner_payment_provider_mode_demo_label",
21789        "owner_payment_provider_mode_live_label",
21790        "owner_payment_provider_credentials_state_label",
21791        "owner_payment_provider_credentials_headline",
21792        "owner_payment_provider_credentials_body",
21793        "owner_payment_provider_client_id_label",
21794        "owner_payment_provider_client_id_placeholder",
21795        "owner_payment_provider_client_secret_label",
21796        "owner_payment_provider_client_secret_placeholder",
21797        "owner_payment_provider_save_credentials_label",
21798        "owner_payment_provider_delete_credentials_label",
21799        "owner_payment_provider_connect_label",
21800        "owner_payment_provider_refresh_label",
21801    ] {
21802        if let Some(value) = super::payment_provider::payment_provider_copy_value(app_root, key) {
21803            params.insert(key.to_owned(), Value::String(value));
21804        }
21805    }
21806    params.insert(
21807        "owner_payment_provider_action_href".to_owned(),
21808        Value::String(format!(
21809            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/test/"
21810        )),
21811    );
21812    params.insert(
21813        "owner_payment_provider_refresh_href".to_owned(),
21814        Value::String(format!(
21815            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/refresh/"
21816        )),
21817    );
21818    params.insert(
21819        "owner_payment_provider_credentials_href".to_owned(),
21820        Value::String(format!(
21821            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/"
21822        )),
21823    );
21824    params.insert(
21825        "owner_payment_provider_credentials_delete_href".to_owned(),
21826        Value::String(format!(
21827            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/credentials/delete/"
21828        )),
21829    );
21830    params.insert(
21831        "owner_payment_provider_mode_href".to_owned(),
21832        Value::String(format!(
21833            "/businesses/{business_slug}/payment-providers/{payment_provider_id}/mode/"
21834        )),
21835    );
21836    render_fragment_with_params(
21837        app_root,
21838        "templates/businesses/fragments/business_edit_external_integrations.html",
21839        params,
21840    )
21841}
21842
21843/// Releases a PostgreSQL runtime configuration.
21844///
21845/// # Parameters
21846///
21847/// - `_config`: Input consumed by [`crate::runtime::json_commands::free_postgresql_runtime_config_runtime_local`].
21848///
21849/// # Returns
21850///
21851/// Returns after [`crate::runtime::json_commands::free_postgresql_runtime_config_runtime_local`] applies its in-place effect.
21852///
21853/// # Examples
21854///
21855/// ```rust,ignore
21856/// let _result = pharos_native::runtime::json_commands::free_postgresql_runtime_config_runtime_local(todo!());
21857/// ```
21858///
21859/// # Related
21860///
21861/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21862pub fn free_postgresql_runtime_config_runtime_local<T>(_config: T) {}
21863
21864/// Finds a business by numeric identifier.
21865///
21866/// # Parameters
21867///
21868/// - `root`: Input consumed by [`crate::runtime::json_commands::find_business_by_id_runtime_local`].
21869/// - `business_id`: Input consumed by [`crate::runtime::json_commands::find_business_by_id_runtime_local`].
21870///
21871/// # Returns
21872///
21873/// Returns [`Some`] when [`crate::runtime::json_commands::find_business_by_id_runtime_local`] can produce a value and [`None`] otherwise.
21874///
21875/// # Performance
21876///
21877/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::find_business_by_id_runtime_local`].
21878///
21879/// # Examples
21880///
21881/// ```rust,ignore
21882/// let _result = pharos_native::runtime::json_commands::find_business_by_id_runtime_local(std::path::Path::new("."), todo!());
21883/// ```
21884///
21885/// # Related
21886///
21887/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21888pub fn find_business_by_id_runtime_local(root: &Value, business_id: i64) -> Option<Value> {
21889    bounded_state_array(root, "businesses")
21890        .iter()
21891        .find(|row| row.get("id").and_then(Value::as_i64) == Some(business_id))
21892        .cloned()
21893}
21894
21895/// Converts a JSON value to an integer without panicking.
21896///
21897/// # Parameters
21898///
21899/// - `value`: Input consumed by [`crate::runtime::json_commands::long_from_value_runtime_local`].
21900///
21901/// # Returns
21902///
21903/// Returns the computed value produced by [`crate::runtime::json_commands::long_from_value_runtime_local`].
21904///
21905/// # Examples
21906///
21907/// ```rust,ignore
21908/// let _result = pharos_native::runtime::json_commands::long_from_value_runtime_local("value");
21909/// ```
21910///
21911/// # Related
21912///
21913/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21914pub fn long_from_value_runtime_local(value: &Value) -> i64 {
21915    super::ops_bridge::long_from_value(value)
21916}
21917
21918/// Builds registration page parameters with one escaped error message.
21919///
21920/// # Parameters
21921///
21922/// - `root`: Input consumed by [`crate::runtime::json_commands::register_page_params_with_error_json`].
21923/// - `error_text`: Input consumed by [`crate::runtime::json_commands::register_page_params_with_error_json`].
21924///
21925/// # Returns
21926///
21927/// Returns [`Some`] when [`crate::runtime::json_commands::register_page_params_with_error_json`] can produce a value and [`None`] otherwise.
21928///
21929/// # Examples
21930///
21931/// ```rust,ignore
21932/// let _result = pharos_native::runtime::json_commands::register_page_params_with_error_json(std::path::Path::new("."), todo!());
21933/// ```
21934///
21935/// # Related
21936///
21937/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21938pub fn register_page_params_with_error_json(root: &Value, error_text: &str) -> Option<String> {
21939    let mut extra = Map::new();
21940    extra.insert("error".into(), Value::String(error_text.into()));
21941    page_params_value(root, "register", extra)
21942}
21943
21944/// Returns a path for a generated admin composition.
21945///
21946/// # Parameters
21947///
21948/// - `root`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_admin_composition_path`].
21949/// - `composition_id`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_admin_composition_path`].
21950///
21951/// # Returns
21952///
21953/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_generated_surface_admin_composition_path`] can produce a value and [`None`] otherwise.
21954///
21955/// # Performance
21956///
21957/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::runtime_generated_surface_admin_composition_path`].
21958///
21959/// # Examples
21960///
21961/// ```rust,ignore
21962/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_admin_composition_path(std::path::Path::new("."), todo!());
21963/// ```
21964///
21965/// # Related
21966///
21967/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
21968pub fn runtime_generated_surface_admin_composition_path(
21969    root: &Value,
21970    composition_id: &str,
21971) -> Option<String> {
21972    root.get("compositions")?
21973        .as_array()?
21974        .iter()
21975        .find(|row| row.get("id").and_then(Value::as_str) == Some(composition_id))
21976        .and_then(|row| row.get("path").and_then(Value::as_str))
21977        .map(ToOwned::to_owned)
21978}
21979
21980/// Finds one named composition section.
21981///
21982/// # Parameters
21983///
21984/// - `composition`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_composition_find_section`].
21985/// - `section_id`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_composition_find_section`].
21986///
21987/// # Returns
21988///
21989/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_generated_surface_composition_find_section`] can produce a value and [`None`] otherwise.
21990///
21991/// # Performance
21992///
21993/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::runtime_generated_surface_composition_find_section`].
21994///
21995/// # Examples
21996///
21997/// ```rust,ignore
21998/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_composition_find_section(todo!(), todo!());
21999/// ```
22000///
22001/// # Related
22002///
22003/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22004pub fn runtime_generated_surface_composition_find_section<'a>(
22005    composition: &'a Value,
22006    section_id: &str,
22007) -> Option<&'a Value> {
22008    composition
22009        .get("sections")?
22010        .as_array()?
22011        .iter()
22012        .find(|row| row.get("id").and_then(Value::as_str) == Some(section_id))
22013}
22014
22015/// Returns whether a composition section is enabled.
22016///
22017/// # Parameters
22018///
22019/// - `section`: Input consumed by [`crate::runtime::json_commands::runtime_generated_surface_composition_section_enabled`].
22020///
22021/// # Returns
22022///
22023/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_generated_surface_composition_section_enabled`] holds and `false` otherwise.
22024///
22025/// # Examples
22026///
22027/// ```rust,ignore
22028/// let _result = pharos_native::runtime::json_commands::runtime_generated_surface_composition_section_enabled("items");
22029/// ```
22030///
22031/// # Related
22032///
22033/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22034pub fn runtime_generated_surface_composition_section_enabled(section: &Value) -> bool {
22035    section
22036        .get("enabled")
22037        .and_then(Value::as_bool)
22038        .unwrap_or(true)
22039}
22040
22041/// Finds a named form in a generated surface document.
22042///
22043/// # Parameters
22044///
22045/// - `surface`: Input consumed by [`crate::runtime::json_commands::runtime_surface_find_form`].
22046/// - `form_id`: Input consumed by [`crate::runtime::json_commands::runtime_surface_find_form`].
22047///
22048/// # Returns
22049///
22050/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_surface_find_form`] can produce a value and [`None`] otherwise.
22051///
22052/// # Performance
22053///
22054/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::runtime_surface_find_form`].
22055///
22056/// # Examples
22057///
22058/// ```rust,ignore
22059/// let _result = pharos_native::runtime::json_commands::runtime_surface_find_form(todo!(), "form");
22060/// ```
22061///
22062/// # Related
22063///
22064/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22065pub fn runtime_surface_find_form<'a>(surface: &'a Value, form_id: &str) -> Option<&'a Value> {
22066    surface
22067        .get("forms")?
22068        .as_array()?
22069        .iter()
22070        .find(|form| form.get("id").and_then(Value::as_str) == Some(form_id))
22071}
22072
22073/// Appends bounded text to a runtime buffer.
22074///
22075/// # Parameters
22076///
22077/// - `output`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_append`].
22078/// - `text`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_append`].
22079///
22080/// # Returns
22081///
22082/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_text_buffer_append`] holds and `false` otherwise.
22083///
22084/// # Examples
22085///
22086/// ```rust,ignore
22087/// let _result = pharos_native::runtime::json_commands::runtime_text_buffer_append(todo!(), "{}");
22088/// ```
22089///
22090/// # Related
22091///
22092/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22093pub fn runtime_text_buffer_append(output: &mut String, text: &str) -> bool {
22094    text_buffer_append_format(output, text)
22095}
22096
22097/// Clears a runtime text buffer.
22098///
22099/// # Parameters
22100///
22101/// - `output`: Input consumed by [`crate::runtime::json_commands::runtime_text_buffer_free`].
22102///
22103/// # Returns
22104///
22105/// Returns after [`crate::runtime::json_commands::runtime_text_buffer_free`] applies its in-place effect.
22106///
22107/// # Examples
22108///
22109/// ```rust,ignore
22110/// let _result = pharos_native::runtime::json_commands::runtime_text_buffer_free(todo!());
22111/// ```
22112///
22113/// # Related
22114///
22115/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22116pub fn runtime_text_buffer_free(output: &mut String) {
22117    output.clear();
22118}
22119
22120/// Renders a service media URL using the canonical media route.
22121///
22122/// # Parameters
22123///
22124/// - `business_slug`: Input consumed by [`crate::runtime::json_commands::dynamic_service_media_url`].
22125/// - `media_url`: Input consumed by [`crate::runtime::json_commands::dynamic_service_media_url`].
22126///
22127/// # Returns
22128///
22129/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_service_media_url`] can produce a value and [`None`] otherwise.
22130///
22131/// # Examples
22132///
22133/// ```rust,ignore
22134/// let _result = pharos_native::runtime::json_commands::dynamic_service_media_url("demo", todo!());
22135/// ```
22136///
22137/// # Related
22138///
22139/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22140pub fn dynamic_service_media_url(business_slug: &str, media_url: &str) -> Option<String> {
22141    super::dynamic::media_disk_path(Path::new("."), business_slug, media_url).or_else(|| {
22142        (!business_slug.is_empty() && !media_url.is_empty()).then(|| {
22143            format!(
22144                "/media/businesses/{business_slug}/{}",
22145                media_url.trim_start_matches('/')
22146            )
22147        })
22148    })
22149}
22150
22151/// Renders a generated admin fragment from an app-owned document.
22152///
22153/// # Parameters
22154///
22155/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_generated_admin_fragment_from_doc`].
22156/// - `relative_path`: Input consumed by [`crate::runtime::json_commands::render_generated_admin_fragment_from_doc`].
22157/// - `params`: Input consumed by [`crate::runtime::json_commands::render_generated_admin_fragment_from_doc`].
22158///
22159/// # Returns
22160///
22161/// Returns [`Some`] when [`crate::runtime::json_commands::render_generated_admin_fragment_from_doc`] can produce a value and [`None`] otherwise.
22162///
22163/// # Examples
22164///
22165/// ```rust,ignore
22166/// let _result = pharos_native::runtime::json_commands::render_generated_admin_fragment_from_doc(std::path::Path::new("apps/dev_docs"), "page", todo!());
22167/// ```
22168///
22169/// # Related
22170///
22171/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22172pub fn render_generated_admin_fragment_from_doc(
22173    app_root: &Path,
22174    relative_path: &str,
22175    params: &Value,
22176) -> Option<String> {
22177    render_shared_asset_fragment_from_doc(app_root, relative_path, params)
22178}
22179
22180/// Tests whether an array contains a numeric value.
22181///
22182/// # Parameters
22183///
22184/// - `array`: Input consumed by [`crate::runtime::json_commands::json_array_contains_long_runtime_local`].
22185/// - `wanted`: Input consumed by [`crate::runtime::json_commands::json_array_contains_long_runtime_local`].
22186///
22187/// # Returns
22188///
22189/// Returns `true` when the condition checked by [`crate::runtime::json_commands::json_array_contains_long_runtime_local`] holds and `false` otherwise.
22190///
22191/// # Performance
22192///
22193/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_array_contains_long_runtime_local`].
22194///
22195/// # Examples
22196///
22197/// ```rust,ignore
22198/// let _result = pharos_native::runtime::json_commands::json_array_contains_long_runtime_local(todo!(), todo!());
22199/// ```
22200///
22201/// # Related
22202///
22203/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22204pub fn json_array_contains_long_runtime_local(array: &Value, wanted: i64) -> bool {
22205    array.as_array().is_some_and(|items| {
22206        items
22207            .iter()
22208            .any(|item| item.as_i64().or_else(|| item.as_str()?.parse().ok()) == Some(wanted))
22209    })
22210}
22211
22212/// Builds login page parameters from a validated error and next path.
22213///
22214/// # Parameters
22215///
22216/// - `root`: Input consumed by [`crate::runtime::json_commands::login_page_params_json`].
22217/// - `error_text`: Input consumed by [`crate::runtime::json_commands::login_page_params_json`].
22218/// - `next_path`: Input consumed by [`crate::runtime::json_commands::login_page_params_json`].
22219///
22220/// # Returns
22221///
22222/// Returns [`Some`] when [`crate::runtime::json_commands::login_page_params_json`] can produce a value and [`None`] otherwise.
22223///
22224/// # Examples
22225///
22226/// ```rust,ignore
22227/// let _result = pharos_native::runtime::json_commands::login_page_params_json(std::path::Path::new("."), todo!(), todo!());
22228/// ```
22229///
22230/// # Related
22231///
22232/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22233pub fn login_page_params_json(root: &Value, error_text: &str, next_path: &str) -> Option<String> {
22234    let mut extra = Map::new();
22235    extra.insert("error".into(), Value::String(error_text.into()));
22236    extra.insert("next".into(), Value::String(next_path.into()));
22237    page_params_value(root, "login", extra)
22238}
22239
22240/// Builds password-reset completion page parameters.
22241///
22242/// # Parameters
22243///
22244/// - `root`: Input consumed by [`crate::runtime::json_commands::password_reset_complete_page_params_json`].
22245/// - `error_text`: Input consumed by [`crate::runtime::json_commands::password_reset_complete_page_params_json`].
22246/// - `token`: Input consumed by [`crate::runtime::json_commands::password_reset_complete_page_params_json`].
22247///
22248/// # Returns
22249///
22250/// Returns [`Some`] when [`crate::runtime::json_commands::password_reset_complete_page_params_json`] can produce a value and [`None`] otherwise.
22251///
22252/// # Examples
22253///
22254/// ```rust,ignore
22255/// let _result = pharos_native::runtime::json_commands::password_reset_complete_page_params_json(std::path::Path::new("."), todo!(), todo!());
22256/// ```
22257///
22258/// # Related
22259///
22260/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22261pub fn password_reset_complete_page_params_json(
22262    root: &Value,
22263    error_text: &str,
22264    token: &str,
22265) -> Option<String> {
22266    let mut extra = Map::new();
22267    extra.insert("error".into(), Value::String(error_text.into()));
22268    extra.insert("token".into(), Value::String(token.into()));
22269    page_params_value(root, "password-reset-complete", extra)
22270}
22271
22272/// Builds password-reset request page parameters.
22273///
22274/// # Parameters
22275///
22276/// - `root`: Input consumed by [`crate::runtime::json_commands::password_reset_request_page_params_json`].
22277/// - `error_text`: Input consumed by [`crate::runtime::json_commands::password_reset_request_page_params_json`].
22278///
22279/// # Returns
22280///
22281/// Returns [`Some`] when [`crate::runtime::json_commands::password_reset_request_page_params_json`] can produce a value and [`None`] otherwise.
22282///
22283/// # Examples
22284///
22285/// ```rust,ignore
22286/// let _result = pharos_native::runtime::json_commands::password_reset_request_page_params_json(std::path::Path::new("."), todo!());
22287/// ```
22288///
22289/// # Related
22290///
22291/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22292pub fn password_reset_request_page_params_json(root: &Value, error_text: &str) -> Option<String> {
22293    let mut extra = Map::new();
22294    extra.insert("error".into(), Value::String(error_text.into()));
22295    page_params_value(root, "password-reset-request", extra)
22296}
22297
22298/// Builds registration page parameters.
22299///
22300/// # Parameters
22301///
22302/// - `root`: Input consumed by [`crate::runtime::json_commands::register_page_params_json`].
22303/// - `error_text`: Input consumed by [`crate::runtime::json_commands::register_page_params_json`].
22304///
22305/// # Returns
22306///
22307/// Returns [`Some`] when [`crate::runtime::json_commands::register_page_params_json`] can produce a value and [`None`] otherwise.
22308///
22309/// # Examples
22310///
22311/// ```rust,ignore
22312/// let _result = pharos_native::runtime::json_commands::register_page_params_json(std::path::Path::new("."), todo!());
22313/// ```
22314///
22315/// # Related
22316///
22317/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22318pub fn register_page_params_json(root: &Value, error_text: &str) -> Option<String> {
22319    register_page_params_with_error_json(root, error_text)
22320}
22321
22322/// Returns at most `limit` UTF-8 bytes from a string without splitting characters.
22323///
22324/// # Parameters
22325///
22326/// - `value`: Input consumed by [`crate::runtime::json_commands::strndup`].
22327/// - `limit`: Input consumed by [`crate::runtime::json_commands::strndup`].
22328///
22329/// # Returns
22330///
22331/// Returns the computed value produced by [`crate::runtime::json_commands::strndup`].
22332///
22333/// # Performance
22334///
22335/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::strndup`].
22336///
22337/// # Examples
22338///
22339/// ```rust,ignore
22340/// let _result = pharos_native::runtime::json_commands::strndup("value", todo!());
22341/// ```
22342///
22343/// # Related
22344///
22345/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22346pub fn strndup(value: &str, limit: usize) -> String {
22347    value.chars().take(limit).collect()
22348}
22349
22350/// Copies a bounded string as an owned Rust value.
22351///
22352/// # Parameters
22353///
22354/// - `value`: Input consumed by [`crate::runtime::json_commands::strdup`].
22355///
22356/// # Returns
22357///
22358/// Returns the computed value produced by [`crate::runtime::json_commands::strdup`].
22359///
22360/// # Examples
22361///
22362/// ```rust,ignore
22363/// let _result = pharos_native::runtime::json_commands::strdup("value");
22364/// ```
22365///
22366/// # Related
22367///
22368/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22369pub fn strdup(value: &str) -> String {
22370    strndup(value, MAX_TEXT_BYTES)
22371}
22372
22373/// Splits a bounded string into delimiter-separated owned fields.
22374///
22375/// # Parameters
22376///
22377/// - `value`: Input consumed by [`crate::runtime::json_commands::strtok_r`].
22378/// - `delimiter`: Input consumed by [`crate::runtime::json_commands::strtok_r`].
22379///
22380/// # Returns
22381///
22382/// Returns the computed value produced by [`crate::runtime::json_commands::strtok_r`].
22383///
22384/// # Performance
22385///
22386/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::strtok_r`].
22387///
22388/// # Examples
22389///
22390/// ```rust,ignore
22391/// let _result = pharos_native::runtime::json_commands::strtok_r("value", todo!());
22392/// ```
22393///
22394/// # Related
22395///
22396/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22397pub fn strtok_r(value: &str, delimiter: &str) -> Vec<String> {
22398    if delimiter.is_empty() {
22399        return vec![value.to_owned()];
22400    }
22401    value
22402        .split(delimiter)
22403        .filter(|part| !part.is_empty())
22404        .map(ToOwned::to_owned)
22405        .take(4096)
22406        .collect()
22407}
22408
22409/// Serializes one JSON string using the canonical escaping policy.
22410///
22411/// # Parameters
22412///
22413/// - `value`: Input consumed by [`crate::runtime::json_commands::encode_json_string_literal`].
22414///
22415/// # Returns
22416///
22417/// Returns [`Some`] when [`crate::runtime::json_commands::encode_json_string_literal`] can produce a value and [`None`] otherwise.
22418///
22419/// # Examples
22420///
22421/// ```rust,ignore
22422/// let _result = pharos_native::runtime::json_commands::encode_json_string_literal("value");
22423/// ```
22424///
22425/// # Related
22426///
22427/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22428pub fn encode_json_string_literal(value: &str) -> Option<String> {
22429    serde_json::to_string(value).ok()
22430}
22431
22432/// Converts bytes to lowercase hexadecimal text.
22433///
22434/// # Parameters
22435///
22436/// - `bytes`: Input consumed by [`crate::runtime::json_commands::bytes_to_hex_logic_local`].
22437///
22438/// # Returns
22439///
22440/// Returns the computed value produced by [`crate::runtime::json_commands::bytes_to_hex_logic_local`].
22441///
22442/// # Performance
22443///
22444/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::bytes_to_hex_logic_local`].
22445///
22446/// # Examples
22447///
22448/// ```rust,ignore
22449/// let _result = pharos_native::runtime::json_commands::bytes_to_hex_logic_local(b"");
22450/// ```
22451///
22452/// # Related
22453///
22454/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22455pub fn bytes_to_hex_logic_local(bytes: &[u8]) -> String {
22456    pharos_runtime_core::support::hex_digest(bytes)
22457}
22458
22459/// Computes HMAC-SHA256 for a bounded message using the shared runtime primitive.
22460///
22461/// # Parameters
22462///
22463/// - `key`: Input consumed by [`crate::runtime::json_commands::hmac_sha256_logic_local`].
22464/// - `data`: Input consumed by [`crate::runtime::json_commands::hmac_sha256_logic_local`].
22465///
22466/// # Returns
22467///
22468/// Returns the computed value produced by [`crate::runtime::json_commands::hmac_sha256_logic_local`].
22469///
22470/// # Examples
22471///
22472/// ```rust,ignore
22473/// let _result = pharos_native::runtime::json_commands::hmac_sha256_logic_local("key", b"");
22474/// ```
22475///
22476/// # Related
22477///
22478/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22479pub fn hmac_sha256_logic_local(key: &[u8], data: &[u8]) -> [u8; 32] {
22480    super::dynamic::hmac_sha256(key, data)
22481}
22482
22483/// Finds one multipart boundary parameter from a Content-Type header.
22484///
22485/// # Parameters
22486///
22487/// - `content_type`: Input consumed by [`crate::runtime::json_commands::dynamic_multipart_boundary`].
22488///
22489/// # Returns
22490///
22491/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_multipart_boundary`] can produce a value and [`None`] otherwise.
22492///
22493/// # Performance
22494///
22495/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_multipart_boundary`].
22496///
22497/// # Examples
22498///
22499/// ```rust,ignore
22500/// let _result = pharos_native::runtime::json_commands::dynamic_multipart_boundary(todo!());
22501/// ```
22502///
22503/// # Related
22504///
22505/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22506pub fn dynamic_multipart_boundary(content_type: &str) -> Option<String> {
22507    let parameter = content_type.split(';').find_map(|part| {
22508        let (name, value) = part.trim().split_once('=')?;
22509        name.eq_ignore_ascii_case("boundary")
22510            .then_some(value.trim().trim_matches('"').to_owned())
22511    })?;
22512    (!parameter.is_empty() && parameter.len() <= 512 && !parameter.contains(['\r', '\n']))
22513        .then_some(parameter)
22514}
22515
22516/// Finds a byte sequence in a bounded byte slice.
22517///
22518/// # Parameters
22519///
22520/// - `haystack`: Input consumed by [`crate::runtime::json_commands::multipart_memmem`].
22521/// - `needle`: Input consumed by [`crate::runtime::json_commands::multipart_memmem`].
22522///
22523/// # Returns
22524///
22525/// Returns [`Some`] when [`crate::runtime::json_commands::multipart_memmem`] can produce a value and [`None`] otherwise.
22526///
22527/// # Examples
22528///
22529/// ```rust,ignore
22530/// let _result = pharos_native::runtime::json_commands::multipart_memmem(todo!(), todo!());
22531/// ```
22532///
22533/// # Related
22534///
22535/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22536pub fn multipart_memmem(haystack: &[u8], needle: &[u8]) -> Option<usize> {
22537    if needle.is_empty() {
22538        return Some(0);
22539    }
22540    haystack
22541        .windows(needle.len())
22542        .position(|window| window == needle)
22543}
22544
22545/// Copies one checked byte range.
22546///
22547/// # Parameters
22548///
22549/// - `body`: Input consumed by [`crate::runtime::json_commands::multipart_dup_range`].
22550/// - `start`: Input consumed by [`crate::runtime::json_commands::multipart_dup_range`].
22551/// - `length`: Input consumed by [`crate::runtime::json_commands::multipart_dup_range`].
22552///
22553/// # Returns
22554///
22555/// Returns [`Some`] when [`crate::runtime::json_commands::multipart_dup_range`] can produce a value and [`None`] otherwise.
22556///
22557/// # Examples
22558///
22559/// ```rust,ignore
22560/// let _result = pharos_native::runtime::json_commands::multipart_dup_range(b"", todo!(), todo!());
22561/// ```
22562///
22563/// # Related
22564///
22565/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22566pub fn multipart_dup_range(body: &[u8], start: usize, length: usize) -> Option<Vec<u8>> {
22567    let end = start.checked_add(length)?;
22568    (end <= body.len() && length <= super::http::PHAROS_HTTP_MAX_MULTIPART_BODY_BYTES)
22569        .then(|| body[start..end].to_vec())
22570}
22571
22572/// Finds a multipart field and returns filename plus content bytes.
22573///
22574/// # Parameters
22575///
22576/// - `body`: Raw multipart request body bytes.
22577/// - `content_type`: Request content type containing the multipart boundary.
22578/// - `field_name`: Multipart form field to extract.
22579///
22580/// # Returns
22581///
22582/// Returns [`Some`] when [`crate::runtime::json_commands::dynamic_multipart_find_part`] can produce a value and [`None`] otherwise.
22583///
22584/// # Performance
22585///
22586/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::dynamic_multipart_find_part`].
22587///
22588/// # Examples
22589///
22590/// ```rust,ignore
22591/// let _result = pharos_native::runtime::json_commands::dynamic_multipart_find_part(b"", todo!(), todo!(), todo!(), todo!());
22592/// ```
22593///
22594/// # Related
22595///
22596/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22597pub fn dynamic_multipart_find_part(
22598    body: &[u8],
22599    content_type: &str,
22600    field_name: &str,
22601) -> Option<(Option<String>, Vec<u8>)> {
22602    let boundary = dynamic_multipart_boundary(content_type)?;
22603    let marker = format!("--{boundary}").into_bytes();
22604    let mut cursor = multipart_memmem(body, &marker)?;
22605    while cursor < body.len() {
22606        let header_start = cursor.checked_add(marker.len() + 2)?;
22607        if header_start > body.len() {
22608            return None;
22609        }
22610        let header_end =
22611            multipart_memmem(&body[header_start..], b"\r\n\r\n")?.checked_add(header_start)?;
22612        let headers = std::str::from_utf8(&body[header_start..header_end]).ok()?;
22613        let disposition = headers.lines().find(|line| {
22614            line.to_ascii_lowercase()
22615                .starts_with("content-disposition:")
22616        })?;
22617        let name = disposition.split(';').find_map(|part| {
22618            let (key, value) = part.trim().split_once('=')?;
22619            key.eq_ignore_ascii_case("name")
22620                .then_some(value.trim().trim_matches('"'))
22621        })?;
22622        let filename = disposition.split(';').find_map(|part| {
22623            let (key, value) = part.trim().split_once('=')?;
22624            key.eq_ignore_ascii_case("filename")
22625                .then_some(value.trim().trim_matches('"').to_owned())
22626        });
22627        let content_start = header_end + 4;
22628        let next_marker = multipart_memmem(&body[content_start..], &marker)
22629            .map(|offset| offset + content_start)?;
22630        let content_end = next_marker.saturating_sub(2);
22631        if name == field_name {
22632            return Some((filename, body[content_start..content_end].to_vec()));
22633        }
22634        cursor = next_marker;
22635    }
22636    None
22637}
22638
22639/// Extracts one multipart text field from an in-memory request body as UTF-8.
22640///
22641/// # Parameters
22642///
22643/// - `body`: Input consumed by [`crate::runtime::json_commands::multipart_extract_text_from_bytes`].
22644/// - `content_type`: Input consumed by [`crate::runtime::json_commands::multipart_extract_text_from_bytes`].
22645/// - `field_name`: Input consumed by [`crate::runtime::json_commands::multipart_extract_text_from_bytes`].
22646///
22647/// # Returns
22648///
22649/// Returns [`Some`] when [`crate::runtime::json_commands::multipart_extract_text_from_bytes`] can produce a value and [`None`] otherwise.
22650///
22651/// # Examples
22652///
22653/// ```rust,ignore
22654/// let _result = pharos_native::runtime::json_commands::multipart_extract_text_from_bytes(b"", todo!(), todo!());
22655/// ```
22656///
22657/// # Related
22658///
22659/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22660pub fn multipart_extract_text_from_bytes(
22661    body: &[u8],
22662    content_type: &str,
22663    field_name: &str,
22664) -> Option<String> {
22665    let (_, bytes) = dynamic_multipart_find_part(body, content_type, field_name)?;
22666    String::from_utf8(bytes).ok()
22667}
22668
22669/// Returns the audit-event count for a state JSON document.
22670///
22671/// # Parameters
22672///
22673/// - `root`: Input consumed by [`crate::runtime::json_commands::audit_event_count`].
22674///
22675/// # Returns
22676///
22677/// Returns the computed value produced by [`crate::runtime::json_commands::audit_event_count`].
22678///
22679/// # Examples
22680///
22681/// ```rust,ignore
22682/// let _result = pharos_native::runtime::json_commands::audit_event_count(std::path::Path::new("."));
22683/// ```
22684///
22685/// # Related
22686///
22687/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22688pub fn audit_event_count(root: &Value) -> String {
22689    bounded_state_array(root, "audit_events").len().to_string()
22690}
22691
22692/// Exports relational state through the selected backend contract.
22693///
22694/// # Parameters
22695///
22696/// - `app_root`: Input consumed by [`crate::runtime::json_commands::export_runtime_state_json`].
22697/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::export_runtime_state_json`].
22698/// - `app_id`: Input consumed by [`crate::runtime::json_commands::export_runtime_state_json`].
22699///
22700/// # Returns
22701///
22702/// Returns [`Some`] when [`crate::runtime::json_commands::export_runtime_state_json`] can produce a value and [`None`] otherwise.
22703///
22704/// # Examples
22705///
22706/// ```rust,ignore
22707/// let _result = pharos_native::runtime::json_commands::export_runtime_state_json(std::path::Path::new("apps/dev_docs"), todo!(), todo!());
22708/// ```
22709///
22710/// # Related
22711///
22712/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22713pub fn export_runtime_state_json(
22714    app_root: &Path,
22715    runtime_conf_path: Option<&Path>,
22716    app_id: Option<&str>,
22717) -> Option<String> {
22718    dynamic_runtime_state_export_json_runtime(app_root, runtime_conf_path, app_id)
22719}
22720
22721/// Imports a validated relational state file through the selected backend contract.
22722///
22723/// # Parameters
22724///
22725/// - `app_root`: Input consumed by [`crate::runtime::json_commands::import_runtime_state_file`].
22726/// - `runtime_conf_path`: Input consumed by [`crate::runtime::json_commands::import_runtime_state_file`].
22727/// - `app_id`: Input consumed by [`crate::runtime::json_commands::import_runtime_state_file`].
22728/// - `state_path`: Input consumed by [`crate::runtime::json_commands::import_runtime_state_file`].
22729/// - `expected_audit_count`: Input consumed by [`crate::runtime::json_commands::import_runtime_state_file`].
22730///
22731/// # Returns
22732///
22733/// Returns the computed value produced by [`crate::runtime::json_commands::import_runtime_state_file`].
22734///
22735/// # Examples
22736///
22737/// ```rust,ignore
22738/// let _result = pharos_native::runtime::json_commands::import_runtime_state_file(std::path::Path::new("apps/dev_docs"), todo!(), todo!(), todo!(), todo!());
22739/// ```
22740///
22741/// # Related
22742///
22743/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22744pub fn import_runtime_state_file(
22745    app_root: &Path,
22746    runtime_conf_path: Option<&Path>,
22747    app_id: Option<&str>,
22748    state_path: &Path,
22749    expected_audit_count: Option<&str>,
22750) -> i32 {
22751    dynamic_runtime_state_import_json_runtime(
22752        app_root,
22753        runtime_conf_path,
22754        app_id,
22755        state_path,
22756        expected_audit_count,
22757    )
22758}
22759
22760/// Returns whether the relational backend is authoritative for this app.
22761///
22762/// # Parameters
22763///
22764/// - `app_root`: Input consumed by [`crate::runtime::json_commands::relational_runtime_authority_enabled_runtime_local`].
22765///
22766/// # Returns
22767///
22768/// Returns `true` when the condition checked by [`crate::runtime::json_commands::relational_runtime_authority_enabled_runtime_local`] holds and `false` otherwise.
22769///
22770/// # Examples
22771///
22772/// ```rust,ignore
22773/// let _result = pharos_native::runtime::json_commands::relational_runtime_authority_enabled_runtime_local(std::path::Path::new("apps/dev_docs"));
22774/// ```
22775///
22776/// # Related
22777///
22778/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22779pub fn relational_runtime_authority_enabled_runtime_local(app_root: &Path) -> bool {
22780    relational_runtime_authority_enabled(app_root)
22781}
22782
22783/// Returns a migration contract document as compact JSON.
22784///
22785/// # Parameters
22786///
22787/// - `path`: Input consumed by [`crate::runtime::json_commands::migration_contract_text_dup_runtime_local`].
22788///
22789/// # Returns
22790///
22791/// Returns [`Some`] when [`crate::runtime::json_commands::migration_contract_text_dup_runtime_local`] can produce a value and [`None`] otherwise.
22792///
22793/// # Examples
22794///
22795/// ```rust,ignore
22796/// let _result = pharos_native::runtime::json_commands::migration_contract_text_dup_runtime_local(std::path::Path::new("fixture.json"));
22797/// ```
22798///
22799/// # Related
22800///
22801/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22802pub fn migration_contract_text_dup_runtime_local(path: &Path) -> Option<String> {
22803    compact(&read_json_file(path)?)
22804}
22805
22806/// Returns a stable file signature based on metadata and content hash.
22807///
22808/// # Parameters
22809///
22810/// - `path`: Input consumed by [`crate::runtime::json_commands::native_file_signature`].
22811///
22812/// # Returns
22813///
22814/// Returns [`Some`] when [`crate::runtime::json_commands::native_file_signature`] can produce a value and [`None`] otherwise.
22815///
22816/// # Examples
22817///
22818/// ```rust,ignore
22819/// let _result = pharos_native::runtime::json_commands::native_file_signature(std::path::Path::new("fixture.json"));
22820/// ```
22821///
22822/// # Related
22823///
22824/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22825pub fn native_file_signature(path: &Path) -> Option<String> {
22826    let bytes = fs::read(path).ok()?;
22827    Some(bytes_to_hex_logic_local(&Sha256::digest(&bytes)))
22828}
22829
22830/// Loads a JSON document from disk with size and object-depth guards.
22831///
22832/// # Parameters
22833///
22834/// - `path`: Input consumed by [`crate::runtime::json_commands::json_doc_load_file`].
22835///
22836/// # Returns
22837///
22838/// Returns [`Some`] when [`crate::runtime::json_commands::json_doc_load_file`] can produce a value and [`None`] otherwise.
22839///
22840/// # Performance
22841///
22842/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_doc_load_file`].
22843///
22844/// # Examples
22845///
22846/// ```rust,ignore
22847/// let _result = pharos_native::runtime::json_commands::json_doc_load_file(std::path::Path::new("fixture.json"));
22848/// ```
22849///
22850/// # Related
22851///
22852/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22853pub fn json_doc_load_file(path: &Path) -> Option<Value> {
22854    let metadata = fs::metadata(path).ok()?;
22855    if !metadata.is_file() || metadata.len() > MAX_TEXT_BYTES as u64 {
22856        return None;
22857    }
22858    serde_json::from_str(&fs::read_to_string(path).ok()?).ok()
22859}
22860
22861/// Reads bounded file bytes for direct runtime consumers.
22862///
22863/// # Parameters
22864///
22865/// - `path`: Input consumed by [`crate::runtime::json_commands::read_file_bytes`].
22866///
22867/// # Returns
22868///
22869/// Returns [`Some`] when [`crate::runtime::json_commands::read_file_bytes`] can produce a value and [`None`] otherwise.
22870///
22871/// # Examples
22872///
22873/// ```rust,ignore
22874/// let _result = pharos_native::runtime::json_commands::read_file_bytes(std::path::Path::new("fixture.json"));
22875/// ```
22876///
22877/// # Related
22878///
22879/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22880pub fn read_file_bytes(path: &Path) -> Option<Vec<u8>> {
22881    let bytes = fs::read(path).ok()?;
22882    (bytes.len() <= MAX_TEXT_BYTES).then_some(bytes)
22883}
22884
22885/// Writes bounded binary data to an app-owned file.
22886///
22887/// # Parameters
22888///
22889/// - `path`: Input consumed by [`crate::runtime::json_commands::write_binary_file`].
22890/// - `bytes`: Input consumed by [`crate::runtime::json_commands::write_binary_file`].
22891///
22892/// # Returns
22893///
22894/// Returns the computed value produced by [`crate::runtime::json_commands::write_binary_file`].
22895///
22896/// # Examples
22897///
22898/// ```rust,ignore
22899/// let _result = pharos_native::runtime::json_commands::write_binary_file(std::path::Path::new("fixture.json"), b"");
22900/// ```
22901///
22902/// # Related
22903///
22904/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22905pub fn write_binary_file(path: &Path, bytes: &[u8]) -> i32 {
22906    if bytes.len() > MAX_TEXT_BYTES {
22907        return 64;
22908    }
22909    super::fs::write_binary_file(path, bytes, 0o640)
22910        .map(|_| 0)
22911        .unwrap_or(69)
22912}
22913
22914/// Applies a base path to root-relative HTML URLs without touching external URLs.
22915///
22916/// # Parameters
22917///
22918/// - `html`: Input consumed by [`crate::runtime::json_commands::apply_base_path_html`].
22919/// - `base_path`: Input consumed by [`crate::runtime::json_commands::apply_base_path_html`].
22920///
22921/// # Returns
22922///
22923/// Returns [`Some`] when [`crate::runtime::json_commands::apply_base_path_html`] can produce a value and [`None`] otherwise.
22924///
22925/// # Examples
22926///
22927/// ```rust,ignore
22928/// let _result = pharos_native::runtime::json_commands::apply_base_path_html(todo!(), "/app");
22929/// ```
22930///
22931/// # Related
22932///
22933/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22934pub fn apply_base_path_html(html: &str, base_path: Option<&str>) -> Option<String> {
22935    template_apply_base_path(html, base_path)
22936}
22937
22938/// Builds layout parameters from a bounded JSON document.
22939///
22940/// # Parameters
22941///
22942/// - `app_root`: Input consumed by [`crate::runtime::json_commands::build_layout_page_params`].
22943/// - `params`: Input consumed by [`crate::runtime::json_commands::build_layout_page_params`].
22944///
22945/// # Returns
22946///
22947/// Returns [`Some`] when [`crate::runtime::json_commands::build_layout_page_params`] can produce a value and [`None`] otherwise.
22948///
22949/// # Examples
22950///
22951/// ```rust,ignore
22952/// let _result = pharos_native::runtime::json_commands::build_layout_page_params(std::path::Path::new("apps/dev_docs"), todo!());
22953/// ```
22954///
22955/// # Related
22956///
22957/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22958pub fn build_layout_page_params(app_root: &Path, params: &Value) -> Option<String> {
22959    let _ = app_root;
22960    compact(params)
22961}
22962
22963/// Finds a declared page file below an app directory.
22964///
22965/// # Parameters
22966///
22967/// - `app_root`: Input consumed by [`crate::runtime::json_commands::runtime_find_declared_page_relative_path_in_directory`].
22968/// - `page_id`: Input consumed by [`crate::runtime::json_commands::runtime_find_declared_page_relative_path_in_directory`].
22969///
22970/// # Returns
22971///
22972/// Returns [`Some`] when [`crate::runtime::json_commands::runtime_find_declared_page_relative_path_in_directory`] can produce a value and [`None`] otherwise.
22973///
22974/// # Examples
22975///
22976/// ```rust,ignore
22977/// let _result = pharos_native::runtime::json_commands::runtime_find_declared_page_relative_path_in_directory(std::path::Path::new("apps/dev_docs"), "home");
22978/// ```
22979///
22980/// # Related
22981///
22982/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
22983pub fn runtime_find_declared_page_relative_path_in_directory(
22984    app_root: &Path,
22985    page_id: &str,
22986) -> Option<String> {
22987    declared_page_relative_path(app_root, page_id)
22988}
22989
22990/// Matches a declared page filename to a validated page identifier.
22991///
22992/// # Parameters
22993///
22994/// - `path`: Input consumed by [`crate::runtime::json_commands::runtime_declared_page_file_matches_id`].
22995/// - `page_id`: Input consumed by [`crate::runtime::json_commands::runtime_declared_page_file_matches_id`].
22996///
22997/// # Returns
22998///
22999/// Returns `true` when the condition checked by [`crate::runtime::json_commands::runtime_declared_page_file_matches_id`] holds and `false` otherwise.
23000///
23001/// # Examples
23002///
23003/// ```rust,ignore
23004/// let _result = pharos_native::runtime::json_commands::runtime_declared_page_file_matches_id(std::path::Path::new("fixture.json"), "home");
23005/// ```
23006///
23007/// # Related
23008///
23009/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23010pub fn runtime_declared_page_file_matches_id(path: &Path, page_id: &str) -> bool {
23011    path.file_stem()
23012        .and_then(|value| value.to_str())
23013        .is_some_and(|value| value == page_id || value.strip_suffix(".page") == Some(page_id))
23014}
23015
23016/// Appends a bounded formatted fragment to a text buffer.
23017///
23018/// # Parameters
23019///
23020/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_format`].
23021/// - `text`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_format`].
23022///
23023/// # Returns
23024///
23025/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_append_format`] holds and `false` otherwise.
23026///
23027/// # Examples
23028///
23029/// ```rust,ignore
23030/// let _result = pharos_native::runtime::json_commands::text_buffer_append_format(todo!(), "{}");
23031/// ```
23032///
23033/// # Related
23034///
23035/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23036pub fn text_buffer_append_format(output: &mut String, text: &str) -> bool {
23037    if output.len().saturating_add(text.len()) > MAX_TEXT_BYTES {
23038        return false;
23039    }
23040    output.push_str(text);
23041    true
23042}
23043
23044/// Performs JSON find string recursive.
23045fn json_find_string_recursive(value: &Value, key: &str) -> Option<String> {
23046    match value {
23047        Value::Object(map) => {
23048            if let Some(text) = map.get(key).and_then(Value::as_str) {
23049                return Some(text.to_owned());
23050            }
23051            map.values()
23052                .find_map(|entry| json_find_string_recursive(entry, key))
23053        }
23054        Value::Array(items) => items
23055            .iter()
23056            .find_map(|entry| json_find_string_recursive(entry, key)),
23057        _ => None,
23058    }
23059}
23060
23061/// Finds a string field in a bounded JSON document.
23062///
23063/// # Parameters
23064///
23065/// - `text`: Input consumed by [`crate::runtime::json_commands::json_find_string`].
23066/// - `key`: Input consumed by [`crate::runtime::json_commands::json_find_string`].
23067///
23068/// # Returns
23069///
23070/// Returns [`Some`] when [`crate::runtime::json_commands::json_find_string`] can produce a value and [`None`] otherwise.
23071///
23072/// # Performance
23073///
23074/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_find_string`].
23075///
23076/// # Examples
23077///
23078/// ```rust,ignore
23079/// let _result = pharos_native::runtime::json_commands::json_find_string("{}", "key");
23080/// ```
23081///
23082/// # Related
23083///
23084/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23085pub fn json_find_string(text: &str, key: &str) -> Option<String> {
23086    if key.is_empty() || text.len() > MAX_TEXT_BYTES {
23087        return None;
23088    }
23089    json_find_string_recursive(&serde_json::from_str(text).ok()?, key)
23090}
23091
23092/// Finds a string field after a caller-selected text offset.
23093///
23094/// # Parameters
23095///
23096/// - `text`: Input consumed by [`crate::runtime::json_commands::json_find_string_after`].
23097/// - `key`: Input consumed by [`crate::runtime::json_commands::json_find_string_after`].
23098/// - `start_at`: Input consumed by [`crate::runtime::json_commands::json_find_string_after`].
23099///
23100/// # Returns
23101///
23102/// Returns [`Some`] when [`crate::runtime::json_commands::json_find_string_after`] can produce a value and [`None`] otherwise.
23103///
23104/// # Performance
23105///
23106/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_find_string_after`].
23107///
23108/// # Examples
23109///
23110/// ```rust,ignore
23111/// let _result = pharos_native::runtime::json_commands::json_find_string_after("{}", "key", todo!());
23112/// ```
23113///
23114/// # Related
23115///
23116/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23117pub fn json_find_string_after(text: &str, key: &str, start_at: &str) -> Option<String> {
23118    let offset = text.find(start_at)?;
23119    json_find_string(&text[offset..], key)
23120}
23121
23122/// Finds a string field inside a named JSON section.
23123///
23124/// # Parameters
23125///
23126/// - `text`: Input consumed by [`crate::runtime::json_commands::json_find_string_in_section`].
23127/// - `section`: Input consumed by [`crate::runtime::json_commands::json_find_string_in_section`].
23128/// - `key`: Input consumed by [`crate::runtime::json_commands::json_find_string_in_section`].
23129///
23130/// # Returns
23131///
23132/// Returns [`Some`] when [`crate::runtime::json_commands::json_find_string_in_section`] can produce a value and [`None`] otherwise.
23133///
23134/// # Performance
23135///
23136/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::json_find_string_in_section`].
23137///
23138/// # Examples
23139///
23140/// ```rust,ignore
23141/// let _result = pharos_native::runtime::json_commands::json_find_string_in_section("{}", "items", "key");
23142/// ```
23143///
23144/// # Related
23145///
23146/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23147pub fn json_find_string_in_section(text: &str, section: &str, key: &str) -> Option<String> {
23148    if section.is_empty() || key.is_empty() {
23149        return None;
23150    }
23151    let root: Value = serde_json::from_str(text).ok()?;
23152    let section = root.get(section)?;
23153    json_find_string_recursive(section, key)
23154}
23155
23156/// Looks up a safe key in a line-oriented runtime configuration file.
23157///
23158/// # Parameters
23159///
23160/// - `path`: Input consumed by [`crate::runtime::json_commands::conf_lookup_value`].
23161/// - `key`: Input consumed by [`crate::runtime::json_commands::conf_lookup_value`].
23162///
23163/// # Returns
23164///
23165/// Returns [`Some`] when [`crate::runtime::json_commands::conf_lookup_value`] can produce a value and [`None`] otherwise.
23166///
23167/// # Performance
23168///
23169/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::conf_lookup_value`].
23170///
23171/// # Examples
23172///
23173/// ```rust,ignore
23174/// let _result = pharos_native::runtime::json_commands::conf_lookup_value(std::path::Path::new("fixture.json"), "key");
23175/// ```
23176///
23177/// # Related
23178///
23179/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23180pub fn conf_lookup_value(path: &Path, key: &str) -> Option<String> {
23181    if key.is_empty()
23182        || key
23183            .bytes()
23184            .any(|byte| !byte.is_ascii_alphanumeric() && byte != b'_')
23185    {
23186        return None;
23187    }
23188    let metadata = fs::metadata(path).ok()?;
23189    if metadata.len() > MAX_TEXT_BYTES as u64 {
23190        return None;
23191    }
23192    fs::read_to_string(path).ok()?.lines().find_map(|line| {
23193        let (candidate, raw) = line.split_once('=')?;
23194        (candidate.trim() == key).then(|| raw.trim().trim_matches(['"', '\'']).to_owned())
23195    })
23196}
23197
23198/// Appends text to a bounded template buffer.
23199///
23200/// # Parameters
23201///
23202/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_append`].
23203/// - `text`: Input consumed by [`crate::runtime::json_commands::text_buffer_append`].
23204///
23205/// # Returns
23206///
23207/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_append`] holds and `false` otherwise.
23208///
23209/// # Examples
23210///
23211/// ```rust,ignore
23212/// let _result = pharos_native::runtime::json_commands::text_buffer_append(todo!(), "{}");
23213/// ```
23214///
23215/// # Related
23216///
23217/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23218pub fn text_buffer_append(output: &mut String, text: &str) -> bool {
23219    text_buffer_append_format(output, text)
23220}
23221
23222/// Appends one character to a bounded template buffer.
23223///
23224/// # Parameters
23225///
23226/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_char`].
23227/// - `value`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_char`].
23228///
23229/// # Returns
23230///
23231/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_append_char`] holds and `false` otherwise.
23232///
23233/// # Examples
23234///
23235/// ```rust,ignore
23236/// let _result = pharos_native::runtime::json_commands::text_buffer_append_char(todo!(), "value");
23237/// ```
23238///
23239/// # Related
23240///
23241/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23242pub fn text_buffer_append_char(output: &mut String, value: char) -> bool {
23243    let mut encoded = [0u8; 4];
23244    text_buffer_append(output, value.encode_utf8(&mut encoded))
23245}
23246
23247/// Escapes and appends one template value.
23248///
23249/// # Parameters
23250///
23251/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_html_escaped`].
23252/// - `text`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_html_escaped`].
23253///
23254/// # Returns
23255///
23256/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_append_html_escaped`] holds and `false` otherwise.
23257///
23258/// # Examples
23259///
23260/// ```rust,ignore
23261/// let _result = pharos_native::runtime::json_commands::text_buffer_append_html_escaped(todo!(), "{}");
23262/// ```
23263///
23264/// # Related
23265///
23266/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23267pub fn text_buffer_append_html_escaped(output: &mut String, text: &str) -> bool {
23268    text_buffer_append(output, &html_escape_text(text))
23269}
23270
23271/// Releases a template buffer.
23272///
23273/// # Parameters
23274///
23275/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_free`].
23276///
23277/// # Returns
23278///
23279/// Returns after [`crate::runtime::json_commands::text_buffer_free`] applies its in-place effect.
23280///
23281/// # Examples
23282///
23283/// ```rust,ignore
23284/// let _result = pharos_native::runtime::json_commands::text_buffer_free(todo!());
23285/// ```
23286///
23287/// # Related
23288///
23289/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23290pub fn text_buffer_free(output: &mut String) {
23291    output.clear();
23292    output.shrink_to_fit();
23293}
23294
23295/// Reserves bounded template buffer capacity.
23296///
23297/// # Parameters
23298///
23299/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_reserve`].
23300/// - `needed_length`: Input consumed by [`crate::runtime::json_commands::text_buffer_reserve`].
23301///
23302/// # Returns
23303///
23304/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_reserve`] holds and `false` otherwise.
23305///
23306/// # Examples
23307///
23308/// ```rust,ignore
23309/// let _result = pharos_native::runtime::json_commands::text_buffer_reserve(todo!(), todo!());
23310/// ```
23311///
23312/// # Related
23313///
23314/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23315pub fn text_buffer_reserve(output: &mut String, needed_length: usize) -> bool {
23316    needed_length <= MAX_TEXT_BYTES
23317        && output
23318            .try_reserve(needed_length.saturating_sub(output.len()))
23319            .is_ok()
23320}
23321
23322/// Takes a template buffer's contents.
23323///
23324/// # Parameters
23325///
23326/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_take`].
23327///
23328/// # Returns
23329///
23330/// Returns [`Some`] when [`crate::runtime::json_commands::text_buffer_take`] can produce a value and [`None`] otherwise.
23331///
23332/// # Examples
23333///
23334/// ```rust,ignore
23335/// let _result = pharos_native::runtime::json_commands::text_buffer_take(todo!());
23336/// ```
23337///
23338/// # Related
23339///
23340/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23341pub fn text_buffer_take(output: &mut String) -> Option<String> {
23342    (!output.is_empty()).then(|| std::mem::take(output))
23343}
23344
23345/// Loads a JSON root from bounded text.
23346///
23347/// # Parameters
23348///
23349/// - `text`: Input consumed by [`crate::runtime::json_commands::load_root_from`].
23350///
23351/// # Returns
23352///
23353/// Returns [`Some`] when [`crate::runtime::json_commands::load_root_from`] can produce a value and [`None`] otherwise.
23354///
23355/// # Performance
23356///
23357/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::load_root_from`].
23358///
23359/// # Examples
23360///
23361/// ```rust,ignore
23362/// let _result = pharos_native::runtime::json_commands::load_root_from("{}");
23363/// ```
23364///
23365/// # Related
23366///
23367/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23368pub fn load_root_from(text: &str) -> Option<Value> {
23369    (text.len() <= MAX_TEXT_BYTES)
23370        .then(|| serde_json::from_str(text).ok())
23371        .flatten()
23372}
23373
23374/// Converts a JSON value to its template text representation.
23375///
23376/// # Parameters
23377///
23378/// - `value`: Input consumed by [`crate::runtime::json_commands::template_value_text`].
23379///
23380/// # Returns
23381///
23382/// Returns the computed value produced by [`crate::runtime::json_commands::template_value_text`].
23383///
23384/// # Examples
23385///
23386/// ```rust,ignore
23387/// let _result = pharos_native::runtime::json_commands::template_value_text("value");
23388/// ```
23389///
23390/// # Related
23391///
23392/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23393pub fn template_value_text(value: &Value) -> String {
23394    match value {
23395        Value::Null => String::new(),
23396        Value::String(text) => text.clone(),
23397        Value::Bool(flag) => flag.to_string(),
23398        Value::Number(number) => number.to_string(),
23399        other => serde_json::to_string(other).unwrap_or_default(),
23400    }
23401}
23402
23403/// Validates whether a template reference uses one approved URL scheme.
23404///
23405/// # Parameters
23406///
23407/// - `text`: Input consumed by [`crate::runtime::json_commands::template_reference_has_allowed_url_scheme`].
23408///
23409/// # Returns
23410///
23411/// Returns `true` when the condition checked by [`crate::runtime::json_commands::template_reference_has_allowed_url_scheme`] holds and `false` otherwise.
23412///
23413/// # Examples
23414///
23415/// ```rust,ignore
23416/// let _result = pharos_native::runtime::json_commands::template_reference_has_allowed_url_scheme("{}");
23417/// ```
23418///
23419/// # Related
23420///
23421/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23422pub fn template_reference_has_allowed_url_scheme(text: &str) -> bool {
23423    template_url_reference_allowed(text)
23424}
23425
23426/// Performs template value usd minor text.
23427fn template_value_usd_minor_text(value: &Value) -> Option<String> {
23428    let minor = match value {
23429        Value::Number(number) => number.as_i64()?,
23430        Value::String(text) => text.parse::<i64>().ok()?,
23431        _ => return None,
23432    };
23433    currency_minor_text(minor, "USD")
23434}
23435
23436/// Formats exact integer minor units for supported currencies without floating-point rounding.
23437pub(super) fn currency_minor_text(amount: i64, currency: &str) -> Option<String> {
23438    let prefix = match currency {
23439        "USD" => "$",
23440        "JPY" => "¥",
23441        "EUR" => "€",
23442        "GBP" => "£",
23443        "CAD" => "CAD ",
23444        "AUD" => "AUD ",
23445        _ => return None,
23446    };
23447    let sign = if amount < 0 { "-" } else { "" };
23448    let absolute = amount.unsigned_abs();
23449    Some(if currency == "JPY" {
23450        format!("{sign}{prefix}{absolute}")
23451    } else {
23452        format!("{sign}{prefix}{}.{:02}", absolute / 100, absolute % 100)
23453    })
23454}
23455
23456/// Classifies a placeholder as text, path, URL, HTML, or formatted USD minor units.
23457///
23458/// # Parameters
23459///
23460/// - `name`: Input consumed by [`crate::runtime::json_commands::template_placeholder_kind`].
23461///
23462/// # Returns
23463///
23464/// Returns the computed value produced by [`crate::runtime::json_commands::template_placeholder_kind`].
23465///
23466/// # Examples
23467///
23468/// ```rust,ignore
23469/// let _result = pharos_native::runtime::json_commands::template_placeholder_kind("name");
23470/// ```
23471///
23472/// # Related
23473///
23474/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23475pub fn template_placeholder_kind(name: &str) -> String {
23476    if name.starts_with("html:") {
23477        "html".to_owned()
23478    } else if name.starts_with("path:") {
23479        "path".to_owned()
23480    } else if name.starts_with("url:") {
23481        "url".to_owned()
23482    } else if name.starts_with("usd_minor:") {
23483        "usd_minor".to_owned()
23484    } else if name.starts_with("currency_minor:") {
23485        "currency_minor".to_owned()
23486    } else {
23487        "text".to_owned()
23488    }
23489}
23490
23491/// Appends a JSON value after applying the placeholder kind security policy.
23492///
23493/// # Parameters
23494///
23495/// - `output`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_template_value`].
23496/// - `value`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_template_value`].
23497/// - `kind`: Input consumed by [`crate::runtime::json_commands::text_buffer_append_template_value`].
23498///
23499/// # Returns
23500///
23501/// Returns `true` when the condition checked by [`crate::runtime::json_commands::text_buffer_append_template_value`] holds and `false` otherwise.
23502///
23503/// # Examples
23504///
23505/// ```rust,ignore
23506/// let _result = pharos_native::runtime::json_commands::text_buffer_append_template_value(todo!(), "value", todo!());
23507/// ```
23508///
23509/// # Related
23510///
23511/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23512pub fn text_buffer_append_template_value(output: &mut String, value: &Value, kind: &str) -> bool {
23513    match kind {
23514        "html" => text_buffer_append(output, &template_value_text(value)),
23515        "path" if template_path_reference_allowed(&template_value_text(value)) => {
23516            text_buffer_append_html_escaped(output, &template_value_text(value))
23517        }
23518        "url" if template_url_reference_allowed(&template_value_text(value)) => {
23519            text_buffer_append_html_escaped(output, &template_value_text(value))
23520        }
23521        "usd_minor" => template_value_usd_minor_text(value)
23522            .is_some_and(|text| text_buffer_append_html_escaped(output, &text)),
23523        "text" => text_buffer_append_html_escaped(output, &template_value_text(value)),
23524        _ => false,
23525    }
23526}
23527
23528/// Renders template text with an explicit default placeholder kind.
23529///
23530/// # Parameters
23531///
23532/// - `template_text`: Input consumed by [`crate::runtime::json_commands::render_template_text_with_default_kind`].
23533/// - `params_root`: Input consumed by [`crate::runtime::json_commands::render_template_text_with_default_kind`].
23534/// - `default_kind`: Input consumed by [`crate::runtime::json_commands::render_template_text_with_default_kind`].
23535///
23536/// # Returns
23537///
23538/// Returns [`Some`] when [`crate::runtime::json_commands::render_template_text_with_default_kind`] can produce a value and [`None`] otherwise.
23539///
23540/// # Performance
23541///
23542/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::render_template_text_with_default_kind`].
23543///
23544/// # Examples
23545///
23546/// ```rust,ignore
23547/// let _result = pharos_native::runtime::json_commands::render_template_text_with_default_kind(todo!(), &serde_json::json!({}), todo!());
23548/// ```
23549///
23550/// # Related
23551///
23552/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23553pub fn render_template_text_with_default_kind(
23554    template_text: &str,
23555    params_root: &Value,
23556    default_kind: &str,
23557) -> Option<String> {
23558    let params = params_root.as_object()?;
23559    let mut output = String::new();
23560    let mut cursor = 0usize;
23561    while let Some(offset) = template_text[cursor..].find('{') {
23562        let open = cursor + offset;
23563        text_buffer_append(&mut output, &template_text[cursor..open]).then_some(())?;
23564        let close = template_text[open + 1..].find('}')? + open + 1;
23565        let raw = &template_text[open + 1..close];
23566        let (kind, key) = raw
23567            .split_once(':')
23568            .map_or((default_kind, raw), |(kind, key)| (kind, key));
23569        if kind == "currency_minor" {
23570            let value = params.get(key)?;
23571            let amount = value.as_i64().or_else(|| value.as_str()?.parse().ok())?;
23572            let text = currency_minor_text(amount, params.get("currency")?.as_str()?)?;
23573            text_buffer_append_html_escaped(&mut output, &text).then_some(())?;
23574        } else {
23575            text_buffer_append_template_value(&mut output, params.get(key)?, kind).then_some(())?;
23576        }
23577        cursor = close + 1;
23578    }
23579    text_buffer_append(&mut output, &template_text[cursor..]).then_some(output)
23580}
23581
23582/// Resolves a shared JSON template fragment.
23583///
23584/// # Parameters
23585///
23586/// - `fragment_name`: Input consumed by [`crate::runtime::json_commands::shared_asset_fragment_path_json`].
23587///
23588/// # Returns
23589///
23590/// Returns `true` when the condition checked by [`crate::runtime::json_commands::shared_asset_fragment_path_json`] holds and `false` otherwise.
23591///
23592/// # Examples
23593///
23594/// ```rust,ignore
23595/// let _result = pharos_native::runtime::json_commands::shared_asset_fragment_path_json(todo!());
23596/// ```
23597///
23598/// # Related
23599///
23600/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23601pub fn shared_asset_fragment_path_json(fragment_name: &str) -> bool {
23602    fragment_name.starts_with("templates/shared/")
23603        && !fragment_name.contains("..")
23604        && !fragment_name.contains('\0')
23605}
23606
23607/// Returns a shared fragment's rendered HTML.
23608///
23609/// # Parameters
23610///
23611/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_json`].
23612/// - `fragment_name`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_json`].
23613/// - `params_root`: Input consumed by [`crate::runtime::json_commands::render_shared_asset_fragment_json`].
23614///
23615/// # Returns
23616///
23617/// Returns [`Some`] when [`crate::runtime::json_commands::render_shared_asset_fragment_json`] can produce a value and [`None`] otherwise.
23618///
23619/// # Examples
23620///
23621/// ```rust,ignore
23622/// let _result = pharos_native::runtime::json_commands::render_shared_asset_fragment_json(std::path::Path::new("apps/dev_docs"), todo!(), &serde_json::json!({}));
23623/// ```
23624///
23625/// # Related
23626///
23627/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23628pub fn render_shared_asset_fragment_json(
23629    app_root: &str,
23630    fragment_name: &str,
23631    params_root: &Value,
23632) -> Option<String> {
23633    shared_asset_fragment_path_json(fragment_name)
23634        .then(|| render_app_fragment_from_doc(app_root, fragment_name, params_root))
23635        .flatten()
23636}
23637
23638/// Renders an app-owned JSON template fragment.
23639///
23640/// # Parameters
23641///
23642/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_app_fragment`].
23643/// - `fragment_name`: Input consumed by [`crate::runtime::json_commands::render_app_fragment`].
23644/// - `params_root`: Input consumed by [`crate::runtime::json_commands::render_app_fragment`].
23645///
23646/// # Returns
23647///
23648/// Returns [`Some`] when [`crate::runtime::json_commands::render_app_fragment`] can produce a value and [`None`] otherwise.
23649///
23650/// # Examples
23651///
23652/// ```rust,ignore
23653/// let _result = pharos_native::runtime::json_commands::render_app_fragment(std::path::Path::new("apps/dev_docs"), todo!(), &serde_json::json!({}));
23654/// ```
23655///
23656/// # Related
23657///
23658/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23659pub fn render_app_fragment(
23660    app_root: &str,
23661    fragment_name: &str,
23662    params_root: &Value,
23663) -> Option<String> {
23664    render_app_fragment_from_doc(app_root, fragment_name, params_root)
23665}
23666
23667/// Renders an app-owned fragment from an in-memory parameter document.
23668///
23669/// # Parameters
23670///
23671/// - `app_root`: Input consumed by [`crate::runtime::json_commands::render_app_fragment_from_doc`].
23672/// - `fragment_name`: Input consumed by [`crate::runtime::json_commands::render_app_fragment_from_doc`].
23673/// - `params_root`: Input consumed by [`crate::runtime::json_commands::render_app_fragment_from_doc`].
23674///
23675/// # Returns
23676///
23677/// Returns [`Some`] when [`crate::runtime::json_commands::render_app_fragment_from_doc`] can produce a value and [`None`] otherwise.
23678///
23679/// # Performance
23680///
23681/// Performance is proportional to the size of the supplied inputs and any parsed or loaded data consumed by [`crate::runtime::json_commands::render_app_fragment_from_doc`].
23682///
23683/// # Examples
23684///
23685/// ```rust,ignore
23686/// let _result = pharos_native::runtime::json_commands::render_app_fragment_from_doc(std::path::Path::new("apps/dev_docs"), todo!(), &serde_json::json!({}));
23687/// ```
23688///
23689/// # Related
23690///
23691/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23692pub fn render_app_fragment_from_doc(
23693    app_root: &str,
23694    fragment_name: &str,
23695    params_root: &Value,
23696) -> Option<String> {
23697    if app_root.is_empty()
23698        || fragment_name.is_empty()
23699        || fragment_name.contains("..")
23700        || Path::new(fragment_name).is_absolute()
23701        || !params_root.is_object()
23702    {
23703        return None;
23704    }
23705    render_template_text_with_default_kind(
23706        &fs::read_to_string(Path::new(app_root).join(fragment_name)).ok()?,
23707        params_root,
23708        "text",
23709    )
23710}
23711
23712/// Reads one JSON document from bounded text.
23713///
23714/// # Parameters
23715///
23716/// - `text`: Input consumed by [`crate::runtime::json_commands::json_doc_load_text`].
23717///
23718/// # Returns
23719///
23720/// Returns [`Some`] when [`crate::runtime::json_commands::json_doc_load_text`] can produce a value and [`None`] otherwise.
23721///
23722/// # Examples
23723///
23724/// ```rust,ignore
23725/// let _result = pharos_native::runtime::json_commands::json_doc_load_text("{}");
23726/// ```
23727///
23728/// # Related
23729///
23730/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23731pub fn json_doc_load_text(text: &str) -> Option<Value> {
23732    load_root_from(text)
23733}
23734
23735/// Releases an optional JSON document.
23736///
23737/// # Parameters
23738///
23739/// - `document`: Input consumed by [`crate::runtime::json_commands::json_doc_free`].
23740///
23741/// # Returns
23742///
23743/// Returns after [`crate::runtime::json_commands::json_doc_free`] applies its in-place effect.
23744///
23745/// # Examples
23746///
23747/// ```rust,ignore
23748/// let _result = pharos_native::runtime::json_commands::json_doc_free(todo!());
23749/// ```
23750///
23751/// # Related
23752///
23753/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23754pub fn json_doc_free(document: &mut Option<Value>) {
23755    *document = None;
23756}
23757
23758/// Returns one object member without cloning it.
23759///
23760/// # Parameters
23761///
23762/// - `object`: Input consumed by [`crate::runtime::json_commands::json_obj_get`].
23763/// - `key`: Input consumed by [`crate::runtime::json_commands::json_obj_get`].
23764///
23765/// # Returns
23766///
23767/// Returns [`Some`] when [`crate::runtime::json_commands::json_obj_get`] can produce a value and [`None`] otherwise.
23768///
23769/// # Examples
23770///
23771/// ```rust,ignore
23772/// let _result = pharos_native::runtime::json_commands::json_obj_get(todo!(), "key");
23773/// ```
23774///
23775/// # Related
23776///
23777/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23778pub fn json_obj_get<'a>(object: &'a Value, key: &str) -> Option<&'a Value> {
23779    object.as_object()?.get(key)
23780}
23781
23782/// Returns one object array member.
23783///
23784/// # Parameters
23785///
23786/// - `object`: Input consumed by [`crate::runtime::json_commands::json_obj_get_array`].
23787/// - `key`: Input consumed by [`crate::runtime::json_commands::json_obj_get_array`].
23788///
23789/// # Returns
23790///
23791/// Returns [`Some`] when [`crate::runtime::json_commands::json_obj_get_array`] can produce a value and [`None`] otherwise.
23792///
23793/// # Examples
23794///
23795/// ```rust,ignore
23796/// let _result = pharos_native::runtime::json_commands::json_obj_get_array(todo!(), "key");
23797/// ```
23798///
23799/// # Related
23800///
23801/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23802pub fn json_obj_get_array<'a>(object: &'a Value, key: &str) -> Option<&'a Vec<Value>> {
23803    json_obj_get(object, key)?.as_array()
23804}
23805
23806/// Duplicates one object string member.
23807///
23808/// # Parameters
23809///
23810/// - `object`: Input consumed by [`crate::runtime::json_commands::json_obj_get_string`].
23811/// - `key`: Input consumed by [`crate::runtime::json_commands::json_obj_get_string`].
23812///
23813/// # Returns
23814///
23815/// Returns [`Some`] when [`crate::runtime::json_commands::json_obj_get_string`] can produce a value and [`None`] otherwise.
23816///
23817/// # Examples
23818///
23819/// ```rust,ignore
23820/// let _result = pharos_native::runtime::json_commands::json_obj_get_string(todo!(), "key");
23821/// ```
23822///
23823/// # Related
23824///
23825/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23826pub fn json_obj_get_string(object: &Value, key: &str) -> Option<String> {
23827    json_obj_get(object, key)?.as_str().map(ToOwned::to_owned)
23828}
23829
23830/// Reads one object integer member with a default.
23831///
23832/// # Parameters
23833///
23834/// - `object`: Input consumed by [`crate::runtime::json_commands::json_obj_get_long_default`].
23835/// - `key`: Input consumed by [`crate::runtime::json_commands::json_obj_get_long_default`].
23836/// - `default_value`: Input consumed by [`crate::runtime::json_commands::json_obj_get_long_default`].
23837///
23838/// # Returns
23839///
23840/// Returns the computed value produced by [`crate::runtime::json_commands::json_obj_get_long_default`].
23841///
23842/// # Examples
23843///
23844/// ```rust,ignore
23845/// let _result = pharos_native::runtime::json_commands::json_obj_get_long_default(todo!(), "key", todo!());
23846/// ```
23847///
23848/// # Related
23849///
23850/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23851pub fn json_obj_get_long_default(object: &Value, key: &str, default_value: i64) -> i64 {
23852    json_obj_get(object, key)
23853        .and_then(Value::as_i64)
23854        .unwrap_or(default_value)
23855}
23856
23857/// Reads a JSON integer value.
23858///
23859/// # Parameters
23860///
23861/// - `value`: Input consumed by [`crate::runtime::json_commands::json_long_from_value`].
23862///
23863/// # Returns
23864///
23865/// Returns [`Some`] when [`crate::runtime::json_commands::json_long_from_value`] can produce a value and [`None`] otherwise.
23866///
23867/// # Examples
23868///
23869/// ```rust,ignore
23870/// let _result = pharos_native::runtime::json_commands::json_long_from_value("value");
23871/// ```
23872///
23873/// # Related
23874///
23875/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23876pub fn json_long_from_value(value: &Value) -> Option<i64> {
23877    value.as_i64()
23878}
23879
23880/// Serializes one JSON value compactly.
23881///
23882/// # Parameters
23883///
23884/// - `value`: Input consumed by [`crate::runtime::json_commands::json_serialize_compact`].
23885///
23886/// # Returns
23887///
23888/// Returns [`Some`] when [`crate::runtime::json_commands::json_serialize_compact`] can produce a value and [`None`] otherwise.
23889///
23890/// # Examples
23891///
23892/// ```rust,ignore
23893/// let _result = pharos_native::runtime::json_commands::json_serialize_compact("value");
23894/// ```
23895///
23896/// # Related
23897///
23898/// - [`crate::runtime::json_commands`] for adjacent helpers that share the same runtime surface.
23899pub fn json_serialize_compact(value: &Value) -> Option<String> {
23900    serde_json::to_string(value).ok()
23901}
23902
23903#[cfg(test)]
23904mod tests {
23905    /// Checks shared template binding, cycle limits and filesystem confinement.
23906    #[test]
23907    fn shared_template_includes_are_bounded_and_confined() {
23908        let workspace = std::path::Path::new("tmp/0.8.4-testing")
23909            .join(format!("template-includes-{}", std::process::id()));
23910        let root = workspace.join("templates");
23911        std::fs::create_dir_all(root.join("fragments")).unwrap();
23912        let page = root.join("page.html");
23913        let fragment = root.join("fragments/form.html");
23914        std::fs::write(&page, "{include:fragments/form.html}").unwrap();
23915        std::fs::write(&fragment, "<label>{name}</label>").unwrap();
23916        assert_eq!(
23917            super::render_file_template(&page, &serde_json::json!({"name":"<script>"})),
23918            Some("<label>&lt;script&gt;</label>".to_owned())
23919        );
23920        std::fs::write(&fragment, "{include:fragments/form.html}").unwrap();
23921        assert!(super::render_file_template(&page, &serde_json::json!({})).is_none());
23922        std::fs::write(&page, "{include:../outside.html}").unwrap();
23923        assert!(super::render_file_template(&page, &serde_json::json!({})).is_none());
23924        #[cfg(unix)]
23925        {
23926            std::fs::write(workspace.join("outside.html"), "outside").unwrap();
23927            std::os::unix::fs::symlink(
23928                "../../outside.html",
23929                fragment.with_file_name("escape.html"),
23930            )
23931            .unwrap();
23932            std::fs::write(&page, "{include:fragments/escape.html}").unwrap();
23933            assert!(super::render_file_template(&page, &serde_json::json!({})).is_none());
23934        }
23935        std::fs::remove_dir_all(workspace).unwrap();
23936    }
23937    #[test]
23938    fn service_initials_include_every_word() {
23939        for name in [
23940            "Initial Consultation (Online)",
23941            "Initial Consultation(Online)",
23942            "() Initial (Consultation) ((Online)) ()",
23943        ] {
23944            assert_eq!(super::dynamic_service_abbreviation(name), "ICO");
23945        }
23946        assert_eq!(super::dynamic_service_abbreviation(" () () "), "");
23947        assert_eq!(
23948            super::dynamic_service_abbreviation("  deep tissue massage therapy  "),
23949            "DTMT"
23950        );
23951        assert_eq!(
23952            super::dynamic_service_abbreviation("énergie relaxante"),
23953            "ÉR"
23954        );
23955        let app_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("apps/ucal");
23956        let visual = super::service_visual_html(
23957            &app_root,
23958            None,
23959            "deep tissue massage therapy",
23960            Some("#123456"),
23961        )
23962        .unwrap();
23963        assert!(visual.contains("DTMT"));
23964        let online = super::service_visual_html(
23965            &app_root,
23966            None,
23967            "Initial Consultation (Online)",
23968            Some("#123456"),
23969        )
23970        .unwrap();
23971        assert!(online.contains("<span>ICO</span>"));
23972    }
23973    #[test]
23974    fn service_order_picker_counts_only_active_services() {
23975        let app_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("apps/ucal");
23976        let state = serde_json::json!({"services": [
23977            {"business_id": 1, "is_active": true, "sort_order": 1},
23978            {"business_id": 1, "is_active": false, "sort_order": 99},
23979            {"business_id": 2, "is_active": true, "sort_order": 1}
23980        ]});
23981        let adding =
23982            super::service_sort_order_options_html(&app_root, &state, 1, 99, true).unwrap();
23983        let editing =
23984            super::service_sort_order_options_html(&app_root, &state, 1, 99, false).unwrap();
23985        assert_eq!(adding.matches("<option").count(), 2);
23986        assert_eq!(editing.matches("<option").count(), 1);
23987        assert!(adding.contains("value=\"2\" selected"));
23988        assert!(editing.contains("value=\"1\" selected"));
23989    }
23990    use super::*;
23991
23992    #[test]
23993    fn appointments_page_params_render_user_appointment_rows() {
23994        let root = serde_json::json!({
23995            "businesses": [{"id": 7, "slug": "lotus-studio", "name": "Lotus Thai Massage"}],
23996            "services": [{"id": 3, "business_id": 7, "name": "Thai Massage", "duration_minutes": 60}],
23997            "appointments": [{
23998                "id": 11,
23999                "user_id": 42,
24000                "business_id": 7,
24001                "service_id": 3,
24002                "date": "2026-09-12",
24003                "time": "13:30",
24004                "status": "confirmed",
24005                "payment_status": "demo"
24006            }]
24007        });
24008        let params = dynamic_appointments_page_params_from_root_json(
24009            &root,
24010            42,
24011            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24012        )
24013        .expect("appointments params");
24014        let params: Value = serde_json::from_str(&params).expect("json params");
24015        let html = params
24016            .get("appointment_items")
24017            .and_then(Value::as_str)
24018            .unwrap_or_default();
24019        assert!(html.contains("Thai Massage"));
24020        assert!(html.contains("Lotus Thai Massage"));
24021        assert!(html.contains("2026-09-12 at 1:30 PM"));
24022        assert!(!html.contains("No appointments"));
24023    }
24024
24025    #[test]
24026    fn user_bookings_page_params_render_persisted_booking_rows() {
24027        let root = serde_json::json!({
24028            "bookings": [{
24029                "id": 4,
24030                "user_id": 9,
24031                "title": "Internal booking",
24032                "date": "2026-09-15",
24033                "time": "10:00",
24034                "status": "confirmed"
24035            }]
24036        });
24037        let params = dynamic_user_bookings_page_params_from_root_json(
24038            &root,
24039            9,
24040            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24041        )
24042        .expect("bookings params");
24043        let params: Value = serde_json::from_str(&params).expect("json params");
24044        let html = params
24045            .get("booking_rows_html")
24046            .and_then(Value::as_str)
24047            .unwrap_or_default();
24048        assert!(html.contains("Internal booking"));
24049        assert!(html.contains("2026-09-15"));
24050        assert!(html.contains("10:00 AM"));
24051        assert!(!html.contains("No bookings yet"));
24052    }
24053
24054    #[test]
24055    fn profile_page_params_render_signed_in_user_state() {
24056        let root = serde_json::json!({
24057            "users": [{
24058                "id": 2,
24059                "email": "customer@example.test",
24060                "display_name": "Customer One",
24061                "full_name": "Customer One",
24062                "phone_number": "555-0102",
24063                "address": "1 Market Road",
24064                "payment_preference": "credit_card"
24065            }],
24066            "businesses": [{"id": 1, "slug": "lotus-studio", "name": "Lotus Thai Massage"}],
24067            "subscriptions": [{"id": 1, "user_id": 2, "business_id": 1}],
24068            "google_calendar_connections": [{"id": 1, "user_id": 2, "connection_status": "connected"}]
24069        });
24070        let params = dynamic_profile_page_params_json(
24071            &root,
24072            2,
24073            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24074        )
24075        .expect("profile");
24076        let params: Value = serde_json::from_str(&params).expect("json params");
24077        assert_eq!(
24078            params.get("full_name").and_then(Value::as_str),
24079            Some("Customer One")
24080        );
24081        assert_eq!(
24082            params
24083                .get("selected_payment_preference")
24084                .and_then(Value::as_str),
24085            Some("credit_card")
24086        );
24087        assert_eq!(
24088            params.get("google_status").and_then(Value::as_str),
24089            Some("connected")
24090        );
24091        assert!(
24092            params
24093                .get("subscription_rows_html")
24094                .and_then(Value::as_str)
24095                .unwrap_or_default()
24096                .contains("Lotus Thai Massage")
24097        );
24098    }
24099
24100    #[test]
24101    fn appointment_detail_params_render_related_records() {
24102        let root = serde_json::json!({
24103            "users": [{"id": 2, "email": "customer@example.test", "full_name": "Customer One"}],
24104            "businesses": [{"id": 7, "owner_id": 1, "slug": "lotus-studio", "name": "Lotus Thai Massage"}],
24105            "services": [{"id": 3, "business_id": 7, "name": "Thai Massage"}],
24106            "appointments": [{
24107                "id": 11,
24108                "user_id": 2,
24109                "business_id": 7,
24110                "service_id": 3,
24111                "date": "2026-09-12",
24112                "time": "13:30",
24113                "status": "confirmed",
24114                "service_cost": "55",
24115                "notes": "Prefers afternoon"
24116            }]
24117        });
24118        let params = dynamic_appointment_detail_page_params_from_root_json(
24119            &root,
24120            2,
24121            11,
24122            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24123        )
24124        .expect("appointment detail");
24125        let params: Value = serde_json::from_str(&params).expect("json params");
24126        assert_eq!(
24127            params.get("service_name").and_then(Value::as_str),
24128            Some("Thai Massage")
24129        );
24130        assert_eq!(
24131            params.get("business_name").and_then(Value::as_str),
24132            Some("Lotus Thai Massage")
24133        );
24134        assert_eq!(
24135            params.get("customer_name").and_then(Value::as_str),
24136            Some("Customer One")
24137        );
24138        assert!(
24139            params
24140                .get("notes_block")
24141                .and_then(Value::as_str)
24142                .unwrap_or_default()
24143                .contains("Prefers afternoon")
24144        );
24145    }
24146
24147    /// Verifies both public states update their accessible label and visual class.
24148    #[test]
24149    fn business_public_toggle_matches_current_state() {
24150        let app_root = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal"));
24151        for (public, label, class) in [
24152            (true, "Public", "business-is-public"),
24153            (false, "Private", "business-is-private"),
24154        ] {
24155            let html = dynamic_render_business_admin_public_state_button_html(
24156                app_root,
24157                "lotus-studio",
24158                public,
24159            )
24160            .expect("toggle");
24161            assert!(html.contains(&format!("aria-label=\"{label}\"")));
24162            assert!(html.contains(&format!("aria-pressed=\"{public}\"")));
24163            assert!(html.contains(class));
24164            assert!(!html.contains("style=\""));
24165        }
24166    }
24167
24168    #[test]
24169    fn business_calendar_params_render_clickable_appointment_dialogs() {
24170        let root = serde_json::json!({
24171            "users": [{"id": 2, "email": "customer@example.test", "full_name": "Customer One"}],
24172            "businesses": [{"id": 7, "owner_id": 1, "slug": "lotus-studio", "name": "Lotus Thai Massage"}],
24173            "services": [{
24174                "id": 3,
24175                "business_id": 7,
24176                "name": "Thai Massage",
24177                "duration_minutes": 45,
24178                "booking_options": [
24179                    {
24180                        "label": "Extended Thai",
24181                        "duration_minutes": 75,
24182                        "cost": "90.00"
24183                    }
24184                ]
24185            }],
24186            "technicians": [{"id": 5, "business_id": 7, "name": "Tech One"}],
24187            "business_availability": [{"id": 1, "business_id": 7, "day_of_week": "Sat", "start_time": "08:00", "end_time": "16:00"}],
24188            "appointments": [{
24189                "id": 11,
24190                "user_id": 2,
24191                "business_id": 7,
24192                "service_id": 3,
24193                "technician_id": 5,
24194                "date": "2026-09-12",
24195                "time": "13:30",
24196                "end_time": "2026-09-12T14:15:00Z",
24197                "service_duration_minutes": 45,
24198                "status": "confirmed",
24199                "payment_status": "paid",
24200                "notes": "Prefers afternoon"
24201            },
24202            {
24203                "id": 12,
24204                "user_id": 2,
24205                "business_id": 7,
24206                "service_id": 3,
24207                "technician_id": 5,
24208                "date": "2026-09-13",
24209                "time": "13:30",
24210                "status": "confirmed",
24211                "payment_status": "paid",
24212                "notes": "Second day"
24213            }]
24214        });
24215        let before = pharos_runtime_core::time::current_timestamp_utc();
24216        let default_params = dynamic_business_calendar_template_params_from_root_json(
24217            &root,
24218            "lotus-studio",
24219            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24220            None,
24221            None,
24222            None,
24223            2,
24224            "csrf-test-token",
24225        )
24226        .expect("default calendar params");
24227        let after = pharos_runtime_core::time::current_timestamp_utc();
24228        let default_params: Value =
24229            serde_json::from_str(&default_params).expect("default json params");
24230        let selected = default_params["selected_date"]
24231            .as_str()
24232            .expect("selected date");
24233        assert!(selected == &before[..10] || selected == &after[..10]);
24234        let params = dynamic_business_calendar_template_params_from_root_json(
24235            &root,
24236            "lotus-studio",
24237            Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/ucal")),
24238            None,
24239            None,
24240            Some("2026-09-12"),
24241            2,
24242            "csrf-test-token",
24243        )
24244        .expect("calendar params");
24245        let params: Value = serde_json::from_str(&params).expect("json params");
24246        let html = params
24247            .get("appointment_rows_html")
24248            .and_then(Value::as_str)
24249            .unwrap_or_default();
24250        assert!(html.contains("data-dialog-open=\"business-calendar-appointment-11\""));
24251        assert!(html.contains("Thai Massage"));
24252        assert!(html.contains("Thai Massage · 45 min"));
24253        assert!(html.contains("Assigned: Tech One"));
24254        assert!(html.contains("<strong>1:30 PM–2:15 PM • 2026-09-12</strong> • Tech One"));
24255        assert!(html.contains("<span>Customer One • customer@example.test</span><span class=\"business-calendar-dialog-payment-status\">paid</span>"));
24256        assert!(html.contains("<strong>Notes:</strong> Prefers afternoon"));
24257        assert!(html.contains("csrf-test-token"));
24258        assert!(html.contains("/appointments/11/cancel/"));
24259        assert!(html.contains("/appointments/11/complete/"));
24260        assert!(html.contains("business-calendar-dialog-title-row"));
24261        assert!(html.contains("aria-label=\"Assign Technician\""));
24262        assert!(!html.contains("title=\"Assign Technician\""));
24263        let internal_dialog_html = params
24264            .get("internal_booking_dialog_html")
24265            .and_then(Value::as_str)
24266            .unwrap_or_default();
24267        assert!(internal_dialog_html.contains("business-calendar-internal-booking"));
24268        assert!(internal_dialog_html.contains("/business/lotus-studio/calendar/appointments/new/"));
24269        assert!(internal_dialog_html.contains("value=\"3\" data-booking-option-index=\"\""));
24270        assert!(internal_dialog_html.contains("Thai Massage · 45 min"));
24271        assert!(internal_dialog_html.contains("data-booking-option-index=\"0\""));
24272        assert!(internal_dialog_html.contains("Thai Massage · Extended Thai · 75 min"));
24273        assert!(internal_dialog_html.contains("data-calendar-booking-option-index"));
24274        assert!(internal_dialog_html.contains("data-calendar-booking-technician"));
24275        let calendar_html = params
24276            .get("calendar_rows_html")
24277            .and_then(Value::as_str)
24278            .unwrap_or_default();
24279        assert!(
24280            calendar_html.contains("background:var(--primary);color:#fff;"),
24281            "selected day remains blue"
24282        );
24283        assert!(
24284            calendar_html.contains("background:#dcfce7;color:#166534;"),
24285            "non-selected booked days render light green"
24286        );
24287        assert!(
24288            calendar_html.contains("has-appointments"),
24289            "booked days include an appointment state class"
24290        );
24291        assert!(
24292            calendar_html.contains("background:var(--gray-200);color:var(--gray-700);"),
24293            "unbooked days remain grey"
24294        );
24295    }
24296
24297    #[test]
24298    fn architect_layout_hides_builder_settings_until_authenticated() {
24299        let app_root = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/apps/architect"));
24300        let anonymous = template_layout_page_html(
24301            app_root,
24302            Some("/architect"),
24303            Some("architect_shell"),
24304            Some("en"),
24305            "Architect Sign In",
24306            "<section>login</section>",
24307            Some("/accounts/login/"),
24308            false,
24309            0,
24310        )
24311        .expect("anonymous architect layout");
24312        assert!(anonymous.contains("Pharos Architect"));
24313        assert!(!anonymous.contains(r#"aria-label="Home""#));
24314        assert!(!anonymous.contains(r#"aria-label="Settings""#));
24315        assert!(!anonymous.contains(r#"aria-label="File""#));
24316        assert!(!anonymous.contains("/architect/settings"));
24317        assert!(!anonymous.contains("/architect/editor"));
24318
24319        let build_user = template_layout_page_html(
24320            app_root,
24321            Some("/architect"),
24322            Some("architect_shell"),
24323            Some("en"),
24324            "Pharos Architect",
24325            "<section>builder</section>",
24326            Some("/"),
24327            true,
24328            1,
24329        )
24330        .expect("build user architect layout");
24331        assert!(build_user.contains(r#"class="nav-icon-button architect-nav-file-link""#));
24332        assert!(build_user.contains(r#"aria-label="Home""#));
24333        assert!(build_user.contains(r#"aria-label="File""#));
24334        assert!(build_user.contains(r#"aria-label="Settings""#));
24335        assert!(build_user.contains(r#"hx-get="/architect/settings""#));
24336        assert!(build_user.contains(r#"hx-get="/architect/editor""#));
24337        assert!(build_user.contains(r#"<span class="nav-button__tooltip">Home</span>"#));
24338        assert!(build_user.contains(r#"<span class="nav-button__tooltip">File</span>"#));
24339        assert!(build_user.contains(r#"<span class="nav-button__tooltip">Settings</span>"#));
24340        assert!(build_user.contains("/architect/settings"));
24341        assert!(build_user.contains("/architect/editor"));
24342        assert!(build_user.contains(r#"aria-label="Log out""#));
24343        assert!(build_user.contains(r#"class="nav-button__icon""#));
24344        assert!(build_user.contains(r#"bi-box-arrow-right"#));
24345        assert!(build_user.contains(r#"action="/architect/accounts/logout/""#));
24346
24347        let admin = template_layout_page_html(
24348            app_root,
24349            Some("/architect"),
24350            Some("architect_shell"),
24351            Some("en"),
24352            "Pharos Architect",
24353            "<section>builder</section>",
24354            Some("/"),
24355            true,
24356            1,
24357        )
24358        .expect("admin architect layout");
24359        assert!(admin.contains(r#"aria-label="Home""#));
24360        assert!(admin.contains(r#"aria-label="File""#));
24361        assert!(admin.contains(r#"aria-label="Settings""#));
24362        assert!(admin.contains(r#"hx-get="/architect/settings""#));
24363        assert!(admin.contains(r#"hx-get="/architect/editor""#));
24364        assert!(admin.contains(r#"<span class="nav-button__tooltip">Settings</span>"#));
24365        assert!(admin.contains("/architect/settings"));
24366    }
24367
24368    #[test]
24369    fn layout_browser_title_prefixes_app_name_without_duplicate_branding() {
24370        let app_root =
24371            std::env::temp_dir().join(format!("pharos-title-test-{}", std::process::id()));
24372        std::fs::create_dir_all(&app_root).expect("create title fixture app");
24373        std::fs::write(
24374            app_root.join("pharos.app.json"),
24375            r#"{"app_id":"commerce_test","name":"Beacon Beats"}"#,
24376        )
24377        .expect("write title fixture manifest");
24378
24379        assert_eq!(
24380            layout_browser_title(&app_root, "Checkout"),
24381            "Beacon Beats - Checkout"
24382        );
24383        assert_eq!(
24384            layout_browser_title(&app_root, "Checkout — Beacon Beats"),
24385            "Beacon Beats - Checkout"
24386        );
24387        assert_eq!(
24388            layout_browser_title(&app_root, "Beacon Beats — Audio that moves the room"),
24389            "Beacon Beats - Audio that moves the room"
24390        );
24391
24392        std::fs::remove_dir_all(app_root).ok();
24393    }
24394}