//! `pic kv ls | get` — read-only KV inspection (G2). //! //! Wraps the read-only `/api/v1/admin/apps/{id}/kv*` surface. There is no //! `set`/`rm` on purpose: KV writes go through `kv::set` in scripts (which //! emit the change events triggers depend on); an admin write would bypass //! that, so the CLI stays read-only (matching the queues precedent). use std::io::Write; use anyhow::Result; use crate::client::Client; use crate::config; use crate::output::{OutputMode, Table}; pub async fn ls( app: Option<&str>, group: Option<&str>, collection: &str, limit: u32, mode: OutputMode, ) -> Result<()> { let creds = config::resolve()?; let client = Client::from_creds(&creds)?; let page = match crate::cmds::require_one_owner(app, group)? { crate::cmds::OwnerRef::App(a) => client.kv_list(a, collection, limit).await?, // §11.6 M4: a group's shared-KV collection. crate::cmds::OwnerRef::Group(g) => client.group_kv_list(g, collection, limit).await?, }; let mut table = Table::new(["key"]); for k in page.keys { table.row([k]); } table.print(mode); if page.next_cursor.is_some() { let _ = writeln!( std::io::stderr(), "(more keys available — raise --limit to see them)" ); } Ok(()) } pub async fn get( app: Option<&str>, group: Option<&str>, collection: &str, key: &str, ) -> Result<()> { let creds = config::resolve()?; let client = Client::from_creds(&creds)?; let value = match crate::cmds::require_one_owner(app, group)? { crate::cmds::OwnerRef::App(a) => client.kv_get(a, collection, key).await?, crate::cmds::OwnerRef::Group(g) => client.group_kv_get(g, collection, key).await?, }; // Always emit the JSON value (pretty) so it pipes cleanly into jq. let pretty = serde_json::to_string_pretty(&value).unwrap_or_else(|_| value.to_string()); println!("{pretty}"); Ok(()) }