1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//! What the cocore modules share: the console's XRPC service, form fields, and one-call actions.
use abi::{Call, Event, Handle};
use serde_json::{Map, Value};
/// The console: API keys (did:web:cocore.dev, served at https://cocore.dev).
pub const CONSOLE: &str = "did:web:cocore.dev#cocore_console";
/// An action's input: its form fields plus `did` and `now`.
pub type Args = Map<String, Value>;
/// A field as a trimmed, non-empty string (numbers too, since forms send strings and JSON sends numbers).
pub fn field(args: &Args, key: &str) -> Option<String> {
match args.get(key)? {
Value::String(s) => Some(s.trim().to_string()).filter(|s| !s.is_empty()),
Value::Number(n) => Some(n.to_string()),
Value::Bool(b) => Some(b.to_string()),
_ => None,
}
}
pub fn required(args: &Args, key: &str) -> Result<String, String> {
field(args, key).ok_or_else(|| format!("{key} is required"))
}
/// One call; its output is the run's result and a failed call the run's error.
pub fn once(event: Event, call: impl FnOnce() -> Result<Call, String>) -> Result<Handle, String> {
Ok(match event {
Event::Start => Handle::new().call(call()?.id("call")),
Event::Result { result, .. } => Handle::new().result(result.into_result()?).done(),
_ => Handle::new(),
})
}