diff --git a/crates/rowbit-cli/src/main.rs b/crates/rowbit-cli/src/main.rs index 51d45af..331c2b2 100644 --- a/crates/rowbit-cli/src/main.rs +++ b/crates/rowbit-cli/src/main.rs @@ -4,6 +4,7 @@ mod grants; mod place; mod review; mod setup; +mod status; mod term; use std::path::PathBuf; @@ -198,6 +199,12 @@ enum Command { /// write, connects the agent clients you pick and sets the review /// page's password. Keeps its files in ~/.rowbit/. Setup(setup::SetupArgs), + /// What Rowbit is connected to: each setup's database, review page, + /// agents and where they're connected + /// + /// Lists every setup in ~/.rowbit and the demo, or with --dir (or in a + /// folder of Rowbit's) that one. Reads files only. + Status(status::StatusArgs), } /// Only Rowbit's state file: for commands that don't touch the database, @@ -394,7 +401,29 @@ async fn serve( engine.set_review_address(&address)?; let engine = std::sync::Arc::new(engine); tokio::spawn(rowbit_web::notify::Notifier::new(engine.clone(), config.notify.clone()).run()); + let setup_json = serde_json::json!({ + "database": database_url(&setup.url) + .ok() + .and_then(|u| rowbit_engine::overview::Database::from_url(&u)), + "dir": setup + .policy + .canonicalize() + .ok() + .and_then(|p| p.parent().map(place::tilde)), + "review_page": format!("{}/", address.trim_end_matches('/')), + "mcp": config.mcp_http.then(|| format!("{}/mcp", address.trim_end_matches('/'))), + "sign_in": match &sign_in { + rowbit_web::SignIn::Oidc(_) => format!( + "through {}", + config.oidc.as_ref().map(|o| o.issuer.as_str()).unwrap_or("an identity provider") + ), + _ => "page password, this machine only".to_owned(), + }, + "notify": config.notify.iter().map(|n| n.name.clone()).collect::>(), + "version": env!("CARGO_PKG_VERSION"), + }); let web = rowbit_web::Web { + setup: setup_json, sign_in, hosts: config.public_host().into_iter().collect(), secure: config.https(), @@ -494,7 +523,7 @@ fn place_files(command: &mut Command) -> anyhow::Result<()> { command: GrantsCommand::Diff { admin } | GrantsCommand::Apply { admin, .. }, } => admin.place()?, Command::Connect(args) => args.place(), - Command::Demo(_) | Command::Setup(_) | Command::Ping { .. } => {} + Command::Demo(_) | Command::Setup(_) | Command::Ping { .. } | Command::Status(_) => {} } Ok(()) } @@ -867,8 +896,9 @@ async fn main() -> anyhow::Result<()> { println!("{agent}"); if let Some((created, last)) = manual { println!( - " {:<10} single token (rowbit agents token, or rowbit connect before 0.2.3): made {}, {}", + " {:<10} {}: made {}, {}", "--single", + rowbit_engine::overview::OWN_TOKEN, review::when(created), used(last) ); @@ -930,6 +960,7 @@ async fn main() -> anyhow::Result<()> { connect::run(args)?; } Command::Setup(args) => setup::run(args).await?, + Command::Status(args) => status::run(args)?, Command::Ping { url } => { let adapter = rowbit_mysql::MySqlAdapter::new(&database_url(&url)?)?; let info = adapter.server_info().await?; diff --git a/crates/rowbit-cli/src/place.rs b/crates/rowbit-cli/src/place.rs index bf30d52..7c1f397 100644 --- a/crates/rowbit-cli/src/place.rs +++ b/crates/rowbit-cli/src/place.rs @@ -74,6 +74,8 @@ pub fn init(args: Vec) -> anyhow::Result> { { None } + // `status` lists every setup unless told which. + None if command.as_deref() == Some("status") => None, None => { let found = home().map(|h| setups(&h)).unwrap_or_default(); match pick(&found) { @@ -292,7 +294,12 @@ pub fn file(path: &mut PathBuf, default: &str) { /// `ROWBIT_DATABASE_URL` from the directory's `env` file, for when neither /// the flag nor the environment set it. pub fn database_url() -> anyhow::Result> { - let Some(dir) = dir() else { return Ok(None) }; + // Run inside a setup's or the demo's folder, that folder. + let dir = match dir() { + Some(dir) => dir, + None if Path::new("rowbit.yml").exists() => Path::new("."), + None => return Ok(None), + }; Ok(read_env_file(&dir.join(ENV_FILE))?.or_else(|| crate::demo::database_url(dir))) } diff --git a/crates/rowbit-cli/src/status.rs b/crates/rowbit-cli/src/status.rs new file mode 100644 index 0000000..2fcdd99 --- /dev/null +++ b/crates/rowbit-cli/src/status.rs @@ -0,0 +1,176 @@ +//! `rowbit status`: every setup on this machine, what database each +//! guards, whether its review page is up, and where its agents are +//! connected. Reads files, opening state files read-only, and never +//! connects to a database. See "What Rowbit is connected to" in +//! docs/spec/setup.md. + +use std::path::{Path, PathBuf}; + +use rowbit_engine::overview::{self, Database}; + +use crate::place::{self, Found}; + +#[derive(clap::Args)] +pub struct StatusArgs {} + +pub fn run(_: StatusArgs) -> anyhow::Result<()> { + let found = setups()?; + if found.is_empty() { + println!("No Rowbit setup on this machine yet. Set one up with: rowbit setup"); + return Ok(()); + } + let width = found.iter().map(|f| f.name.len()).max().unwrap_or(0); + for (i, f) in found.iter().enumerate() { + if i > 0 { + println!(); + } + for (j, line) in describe(f).iter().enumerate() { + let name = if j == 0 { f.name.as_str() } else { "" }; + println!("{name: anyhow::Result> { + let here = match place::dir() { + Some(d) => Some(d.to_owned()), + None if Path::new("rowbit.yml").exists() => Some(std::env::current_dir()?), + None => None, + }; + if let Some(dir) = here { + let dir = dir.canonicalize().unwrap_or(dir); + let name = dir + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("here") + .to_owned(); + return Ok(vec![Found { name, dir }]); + } + Ok(place::home().map(|h| place::setups(&h)).unwrap_or_default()) +} + +/// The lines `rowbit status` prints for one setup. +fn describe(f: &Found) -> Vec { + let dir = &f.dir; + let mut lines = vec![place::tilde(dir)]; + lines.push(match database_url(dir) { + Ok(Some(url)) => match Database::from_url(&url) { + Some(db) => format!("database: {}", db.line()), + None => "database: the URL in the env file doesn't parse".into(), + }, + Ok(None) => "database: no URL (no env file)".into(), + Err(e) => format!("database: {e:#}"), + }); + let address = server_address(dir); + lines.push(format!( + "review page: {}, {}{}", + crate::term::link(&format!("{}/", address.base().trim_end_matches('/'))), + if rowbit_answers(address.listen) { + // Some Rowbit: two setups on one address can't tell which. + "a Rowbit answers there" + } else { + "not running" + }, + match held(dir) { + Ok(Some(0)) => ", nothing held".to_owned(), + Ok(Some(n)) => format!(", {n} held"), + Ok(None) => String::new(), + Err(e) => format!(", couldn't read rowbit.db: {e:#}"), + } + )); + let mut connected = false; + match agents(dir) { + Ok(agents) => { + for a in agents { + lines.push(format!("agent {}: {}", a.id, a.rules_line())); + if a.connections.is_empty() { + lines.push( + " not connected over HTTP; `rowbit connect ` connects it".into(), + ); + } + for c in a.connections { + connected = true; + lines.push(format!( + " {:<10} {} ({})", + c.id, + c.label, + c.used_ms + .map(|u| format!("last used {}", crate::review::when(u))) + .unwrap_or_else(|| "never used".into()) + )); + } + } + } + Err(e) => lines.push(format!("agents: {e:#}")), + } + if connected { + lines.push(format!( + "sign one out: rowbit agents revoke --connection (or --single) --dir {}", + crate::connect::shell_quote(&dir.display().to_string()) + )); + } + lines +} + +/// Whether a Rowbit review page answers at `addr`: its sign-in page, not +/// just anything listening. +fn rowbit_answers(addr: std::net::SocketAddr) -> bool { + use std::io::{Read, Write}; + let timeout = std::time::Duration::from_millis(300); + let Ok(mut s) = std::net::TcpStream::connect_timeout(&addr, timeout) else { + return false; + }; + let _ = s.set_read_timeout(Some(timeout)); + let _ = s.set_write_timeout(Some(timeout)); + if write!(s, "GET /login HTTP/1.0\r\nHost: {addr}\r\n\r\n").is_err() { + return false; + } + let mut body = Vec::new(); + let _ = s.take(16 * 1024).read_to_end(&mut body); + String::from_utf8_lossy(&body).contains("Sign in to Rowbit") +} + +fn database_url(dir: &Path) -> anyhow::Result> { + Ok( + place::read_env_file(&dir.join(place::ENV_FILE))? + .or_else(|| crate::demo::database_url(dir)), + ) +} + +fn server_address(dir: &Path) -> rowbit_web::config::Address { + std::fs::read_to_string(dir.join("rowbit-server.yml")) + .ok() + .and_then(|src| rowbit_web::config::ServerConfig::address(&src).ok()) + .unwrap_or_default() +} + +/// The setup's state file, read-only; `None` if it has none yet. +fn store(dir: &Path) -> anyhow::Result> { + let path: PathBuf = dir.join("rowbit.db"); + if !path.exists() { + return Ok(None); + } + Ok(Some(rowbit_store::Store::open_read_only(&path)?)) +} + +fn held(dir: &Path) -> anyhow::Result> { + let Some(store) = store(dir)? else { + return Ok(None); + }; + Ok(Some(store.list(rowbit_core::change::State::Held)?.len())) +} + +fn agents(dir: &Path) -> anyhow::Result> { + let src = std::fs::read_to_string(dir.join("rowbit.yml"))?; + let policy = rowbit_policy::PolicyFile::from_yaml(&src)?; + // A setup that has never run has no tokens; one whose state can't be + // read says so, rather than claiming nobody is connected. + let store = match store(dir).map_err(|e| anyhow::anyhow!("couldn't read rowbit.db: {e:#}"))? { + Some(s) => s, + None => rowbit_store::Store::open_in_memory()?, + }; + Ok(overview::agents(&policy, &store)?) +} diff --git a/crates/rowbit-cli/tests/connect.rs b/crates/rowbit-cli/tests/connect.rs index feab8a5..4a9bd4d 100644 --- a/crates/rowbit-cli/tests/connect.rs +++ b/crates/rowbit-cli/tests/connect.rs @@ -339,6 +339,18 @@ fn a_project_folder_finds_the_setup_in_rowbit_home() { assert!(agents.contains("coding-agent no token"), "{agents}"); let (ok, out) = in_app(&["connect", "claude-code", "--force"]); assert!(ok, "{out}"); + // `rowbit status` says what it guards, without the password. + let (ok, status) = in_app(&["status"]); + assert!(ok, "{status}"); + assert!( + status.contains("shop ~/.rowbit/shop") + && status.contains("database: shop on h:3306 as u, no TLS") + && status.contains("not running") + && status.contains("agent coding-agent: ") + && status.contains(" Claude Code in "), + "{status}" + ); + assert!(!status.contains(":p@"), "{status}"); // Two, and neither the default: Rowbit asks which. std::fs::create_dir_all(c.home.join(".rowbit/other")).unwrap(); diff --git a/crates/rowbit-engine/src/lib.rs b/crates/rowbit-engine/src/lib.rs index a2976f9..b14d2be 100644 --- a/crates/rowbit-engine/src/lib.rs +++ b/crates/rowbit-engine/src/lib.rs @@ -26,6 +26,8 @@ use rowbit_policy::{ }; use rowbit_store::{AuditEvent, Change, ChangeId, NewDelivery, Review, Store, StoreError}; pub use rowbit_store::{Delivery, DeliveryOutcome}; + +pub mod overview; use thiserror::Error; #[derive(Debug, Error)] @@ -558,6 +560,12 @@ impl Engine { Ok(agent.filter(|a| self.policy.agents.contains_key(a))) } + /// Each agent in `rowbit.yml`, its rules in brief and where it is + /// connected. + pub fn agents_overview(&self) -> Result, EngineError> { + Ok(overview::agents(&self.policy, &self.store())?) + } + /// Checks the whole audit log; see [`Store::verify`]. pub fn verify(&self) -> Result, EngineError> { Ok(self.store().verify()?) diff --git a/crates/rowbit-engine/src/overview.rs b/crates/rowbit-engine/src/overview.rs new file mode 100644 index 0000000..75f942a --- /dev/null +++ b/crates/rowbit-engine/src/overview.rs @@ -0,0 +1,175 @@ +//! What a setup is connected to, for `rowbit status` and the review page's +//! Setup view: the database without its password, each agent's rules in +//! brief, and where each agent is connected. See "What Rowbit is +//! connected to" in docs/spec/setup.md. + +use rowbit_policy::{Decision, Mode, PolicyFile}; +use rowbit_store::{Store, StoreError}; +use serde::Serialize; + +/// The database a URL names. Never the password. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct Database { + pub host: String, + pub port: u16, + pub database: String, + pub user: String, + /// "no TLS", "TLS, certificate and host name checked", ... + pub tls: String, +} + +impl Database { + pub fn from_url(url: &str) -> Option { + let opts = rowbit_mysql::url::opts(url).ok()?; + Some(Database { + host: opts.ip_or_hostname().to_owned(), + port: opts.tcp_port(), + database: opts.db_name().unwrap_or_default().to_owned(), + user: opts.user().unwrap_or_default().to_owned(), + tls: rowbit_mysql::url::describe(&opts).to_owned(), + }) + } + + /// "shop on db.internal:3306 as rowbit, TLS ..." + pub fn line(&self) -> String { + format!( + "{} on {}:{} as {}, {}", + self.database, self.host, self.port, self.user, self.tls + ) + } +} + +/// One agent in `rowbit.yml`, and where it is connected. +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct Agent { + pub id: String, + pub description: Option, + /// "enforce" or "shadow". + pub mode: &'static str, + /// What happens to a write no rule matches: "allow", "hold", "block". + pub default: &'static str, + pub rules: usize, + pub scoped: bool, + pub connections: Vec, +} + +impl Agent { + /// "holds every write", "3 rules, else holds", ... + pub fn rules_line(&self) -> String { + let default = match self.default { + "allow" => "allows", + "block" => "refuses", + _ => "holds", + }; + let mut s = match self.rules { + 0 => format!("{default} every write"), + 1 => format!("1 rule, else {default}"), + n => format!("{n} rules, else {default}"), + }; + if self.mode == "shadow" { + s.push_str(" (shadow mode: logged, not enforced)"); + } + if self.scoped { + s.push_str(", scoped"); + } + s + } +} + +/// A token an agent signs in with over HTTP: one per client entry +/// `rowbit connect` made, and the one `rowbit agents token` made. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct Connection { + /// What `rowbit agents revoke --connection` takes, or + /// `--single` for the single token. + pub id: String, + /// "Claude Code in ~/projects/app" + pub label: String, + pub created_ms: i64, + pub used_ms: Option, +} + +/// The label of the token `rowbit agents token` makes. +pub const OWN_TOKEN: &str = "single token (rowbit agents token, or rowbit connect before 0.2.3)"; + +pub fn agents(policy: &PolicyFile, store: &Store) -> Result, StoreError> { + let tokens = store.connection_tokens()?; + let mut out = Vec::new(); + for (id, a) in &policy.agents { + let mut connections = Vec::new(); + if let Some((created_ms, used_ms)) = store.agent_token_times(id)? { + connections.push(Connection { + id: "--single".into(), + label: OWN_TOKEN.into(), + created_ms, + used_ms, + }); + } + connections.extend( + tokens + .iter() + .filter(|t| &t.agent == id) + .map(|t| Connection { + id: t.id.clone(), + label: t.label.clone(), + created_ms: t.created_ms, + used_ms: t.used_ms, + }), + ); + out.push(Agent { + id: id.clone(), + description: a.description.clone(), + mode: match a.mode { + Mode::Enforce => "enforce", + Mode::Shadow => "shadow", + }, + default: match a.default { + Decision::Allow => "allow", + Decision::Hold => "hold", + Decision::Block => "block", + }, + rules: a.rules.len(), + scoped: a.scopes.is_some(), + connections, + }); + } + Ok(out) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn the_database_comes_without_its_password() { + let d = Database::from_url( + "mysql://rowbit:s3cret@db.internal:3307/shop?ssl-mode=VERIFY_IDENTITY", + ) + .unwrap(); + assert_eq!( + d.line(), + "shop on db.internal:3307 as rowbit, TLS, certificate and host name checked" + ); + assert!(!format!("{d:?}").contains("s3cret")); + } + + #[test] + fn agents_list_their_rules_and_connections() { + let policy = PolicyFile::from_yaml( + "version: 0\nagents:\n bot:\n default: hold\n ops:\n mode: shadow\n default: block\n rules:\n - name: no deletes\n when: { statement: delete }\n then: block\n", + ) + .unwrap(); + let mut store = Store::open_in_memory().unwrap(); + store + .issue_connection_token("bot", "Claude Code in ~/app") + .unwrap(); + let agents = agents(&policy, &store).unwrap(); + assert_eq!(agents[0].rules_line(), "holds every write"); + assert_eq!(agents[0].connections[0].label, "Claude Code in ~/app"); + assert_eq!( + agents[1].rules_line(), + "1 rule, else refuses (shadow mode: logged, not enforced)" + ); + assert!(agents[1].connections.is_empty()); + } +} diff --git a/crates/rowbit-mcp/tests/attacks.rs b/crates/rowbit-mcp/tests/attacks.rs index 4cf8c39..2e0a72d 100644 --- a/crates/rowbit-mcp/tests/attacks.rs +++ b/crates/rowbit-mcp/tests/attacks.rs @@ -478,6 +478,7 @@ async fn approving_through_the_review_page(var: &str, table: &str) { let page = rowbit_web::router( w.engine.clone(), rowbit_web::Web { + setup: serde_json::Value::Null, sign_in: rowbit_web::SignIn::Password { hash: rowbit_web::hash_password(&rowbit_web::new_password()), }, diff --git a/crates/rowbit-store/src/lib.rs b/crates/rowbit-store/src/lib.rs index f8b06c5..dd7dd0a 100644 --- a/crates/rowbit-store/src/lib.rs +++ b/crates/rowbit-store/src/lib.rs @@ -292,6 +292,17 @@ impl Store { Self::init(Connection::open(path)?) } + /// Opens an existing store for reading only: no schema set up, nothing + /// written. For `rowbit status`, which looks at other setups' files. + pub fn open_read_only(path: &Path) -> Result { + let conn = Connection::open_with_flags( + path, + rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY | rusqlite::OpenFlags::SQLITE_OPEN_NO_MUTEX, + )?; + conn.busy_timeout(Duration::from_secs(5))?; + Ok(Store { conn }) + } + pub fn open_in_memory() -> Result { Self::init(Connection::open_in_memory()?) } diff --git a/crates/rowbit-web/dist/assets/app.css b/crates/rowbit-web/dist/assets/app.css index c4db110..1e2c9f6 100644 --- a/crates/rowbit-web/dist/assets/app.css +++ b/crates/rowbit-web/dist/assets/app.css @@ -1,2 +1,2 @@ -:root{--bg:#f4f6fa;--surface:#fff;--ink:#141a2b;--muted:#59627a;--line:#d9deea;--accent:#2b47c9;--before:#a03030;--after:#17794a;--held:#a86300;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@media (prefers-color-scheme:dark){:root{--bg:#0d111c;--surface:#151b2b;--ink:#e6e9f2;--muted:#9aa3bb;--line:#283149;--accent:#8ea2ff;--before:#ff8a8a;--after:#5fd39a;--held:#f0b04a;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}*{box-sizing:border-box}body{background:var(--bg);color:var(--ink);margin:0;font:15px/1.5 system-ui,-apple-system,Segoe UI,sans-serif}a{color:var(--accent)}header{border-bottom:1px solid var(--line);background:var(--surface);flex-wrap:wrap;align-items:center;gap:20px;padding:10px 16px;display:flex}header .brand{color:var(--ink);font-weight:700;text-decoration:none}header nav{gap:14px;display:flex}header nav a{color:var(--muted);text-decoration:none}header nav a.active{color:var(--ink);font-weight:600}header .who{color:var(--muted);margin-left:auto}main{max-width:1100px;margin:0 auto;padding:16px}h1{margin:8px 0 12px;font-size:1.4rem}h2{margin:24px 0 8px;font-size:1.1rem}section,.card{background:var(--surface);border:1px solid var(--line);border-radius:8px;margin:12px 0;padding:14px 16px;display:block}.card{color:inherit;text-decoration:none}.card:hover,.card:focus-visible{border-color:var(--accent)}.card-top{flex-wrap:wrap;align-items:baseline;gap:12px;display:flex}.card-top h1{margin:0}pre{white-space:pre-wrap;word-break:break-word;background:var(--bg);border-radius:4px;padding:8px 10px}code{font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:.9em}.scroll{overflow-x:auto}table{border-collapse:collapse;width:100%;margin:8px 0}th,td{text-align:left;border-bottom:1px solid var(--line);vertical-align:top;padding:4px 8px}td{white-space:pre-wrap;word-break:break-word}tr.first td{border-top:2px solid var(--line)}td.before{color:var(--before)}td.after{color:var(--after)}td.same{color:var(--muted)}.nowrap{white-space:nowrap}i.null{color:var(--muted)}.binary,.number{font-family:ui-monospace,SF Mono,Menlo,monospace}.muted{color:var(--muted)}.small{font-size:.85rem}.error{color:var(--before)}.ok{color:var(--after)}.actions{flex-wrap:wrap;align-items:end;gap:16px;margin-top:12px;display:flex}.actions form,.filters{flex-wrap:wrap;align-items:end;gap:8px;display:flex}label{color:var(--muted);flex-direction:column;gap:2px;font-size:.85rem;display:flex}label.inline{flex-direction:row;gap:6px;margin-left:12px;display:inline-flex}input,select,button{font:inherit;border:1px solid var(--line);background:var(--surface);color:var(--ink);border-radius:4px;padding:4px 10px}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}button.approve{background:var(--accent);color:#fff;border-color:var(--accent)}button.link{color:var(--accent);background:0 0;border:0;padding:0}.state{background:var(--bg);border-radius:3px;padding:1px 7px;font-family:ui-monospace,monospace;font-size:.8rem}.state.held{color:var(--held)}.state.applied,.state.approved{color:var(--after)}.state.rejected,.state.failed{color:var(--before)}.pager{align-items:center;gap:12px;display:flex}:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.shadow{color:var(--held)} +:root{--bg:#f4f6fa;--surface:#fff;--ink:#141a2b;--muted:#59627a;--line:#d9deea;--accent:#2b47c9;--before:#a03030;--after:#17794a;--held:#a86300;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@media (prefers-color-scheme:dark){:root{--bg:#0d111c;--surface:#151b2b;--ink:#e6e9f2;--muted:#9aa3bb;--line:#283149;--accent:#8ea2ff;--before:#ff8a8a;--after:#5fd39a;--held:#f0b04a;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}*{box-sizing:border-box}body{background:var(--bg);color:var(--ink);margin:0;font:15px/1.5 system-ui,-apple-system,Segoe UI,sans-serif}a{color:var(--accent)}header{border-bottom:1px solid var(--line);background:var(--surface);flex-wrap:wrap;align-items:center;gap:20px;padding:10px 16px;display:flex}header .brand{color:var(--ink);font-weight:700;text-decoration:none}header nav{gap:14px;display:flex}header nav a{color:var(--muted);text-decoration:none}header nav a.active{color:var(--ink);font-weight:600}header .who{color:var(--muted);margin-left:auto}main{max-width:1100px;margin:0 auto;padding:16px}h1{margin:8px 0 12px;font-size:1.4rem}h2{margin:24px 0 8px;font-size:1.1rem}section,.card{background:var(--surface);border:1px solid var(--line);border-radius:8px;margin:12px 0;padding:14px 16px;display:block}.card{color:inherit;text-decoration:none}.card:hover,.card:focus-visible{border-color:var(--accent)}.card-top{flex-wrap:wrap;align-items:baseline;gap:12px;display:flex}.card-top h1{margin:0}pre{white-space:pre-wrap;word-break:break-word;background:var(--bg);border-radius:4px;padding:8px 10px}code{font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:.9em}.scroll{overflow-x:auto}table{border-collapse:collapse;width:100%;margin:8px 0}th,td{text-align:left;border-bottom:1px solid var(--line);vertical-align:top;padding:4px 8px}td{white-space:pre-wrap;word-break:break-word}tr.first td{border-top:2px solid var(--line)}td.before{color:var(--before)}td.after{color:var(--after)}td.same{color:var(--muted)}.nowrap{white-space:nowrap}i.null{color:var(--muted)}.binary,.number{font-family:ui-monospace,SF Mono,Menlo,monospace}.muted{color:var(--muted)}.small{font-size:.85rem}.error{color:var(--before)}.ok{color:var(--after)}.actions{flex-wrap:wrap;align-items:end;gap:16px;margin-top:12px;display:flex}.actions form,.filters{flex-wrap:wrap;align-items:end;gap:8px;display:flex}label{color:var(--muted);flex-direction:column;gap:2px;font-size:.85rem;display:flex}label.inline{flex-direction:row;gap:6px;margin-left:12px;display:inline-flex}input,select,button{font:inherit;border:1px solid var(--line);background:var(--surface);color:var(--ink);border-radius:4px;padding:4px 10px}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}button.approve{background:var(--accent);color:#fff;border-color:var(--accent)}button.link{color:var(--accent);background:0 0;border:0;padding:0}.state{background:var(--bg);border-radius:3px;padding:1px 7px;font-family:ui-monospace,monospace;font-size:.8rem}.state.held{color:var(--held)}.state.applied,.state.approved{color:var(--after)}.state.rejected,.state.failed{color:var(--before)}.pager{align-items:center;gap:12px;display:flex}:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.shadow{color:var(--held)}header .guarding{color:var(--muted);font-size:.9rem;text-decoration:none}header .guarding:hover,header .guarding code{color:var(--ink)}.facts{grid-template-columns:max-content 1fr;gap:4px 16px;margin:0;display:grid}.facts dt{color:var(--muted)}.facts dd{overflow-wrap:anywhere;margin:0}h3{margin:16px 0 4px;font-size:1rem} /*$vite$:1*/ \ No newline at end of file diff --git a/crates/rowbit-web/dist/assets/app.js b/crates/rowbit-web/dist/assets/app.js index 4fb2e41..744954b 100644 --- a/crates/rowbit-web/dist/assets/app.js +++ b/crates/rowbit-web/dist/assets/app.js @@ -1,6 +1,6 @@ -var e=Array.isArray,t=Array.prototype.indexOf,n=Array.prototype.includes,r=Array.from,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyDescriptors,s=Object.prototype,c=Array.prototype,l=Object.getPrototypeOf,u=Object.isExtensible,d=()=>{};function f(e){for(var t=0;t{e=n,t=r}),resolve:e,reject:t}}function m(e,t){if(Array.isArray(e))return e;if(t===void 0||!(Symbol.iterator in e))return Array.from(e);let n=[];for(let r of e)if(n.push(r),n.length===t)break;return n}var h=1024,g=2048,_=4096,v=8192,y=16384,b=32768,x=1<<25,S=65536,ee=1<<19,te=1<<20,ne=1<<25,re=1<<21,ie=1<<22,ae=1<<23,oe=Symbol(`$state`),se=Symbol(`component`),ce=Symbol(``),le=Symbol(`attributes`),ue=Symbol(`class`),de=Symbol(`style`),fe=Symbol(`text`),pe=Symbol(`form reset`),me=new class extends Error{name=`StaleReactionError`;message="The reaction that called `getAbortSignal()` was re-run or destroyed"},he=!!globalThis.document?.contentType&&globalThis.document.contentType.includes(`xml`),ge={},C=Symbol(`uninitialized`),_e=`http://www.w3.org/1999/xhtml`;function ve(){console.warn(`https://svelte.dev/e/derived_inert`)}function ye(e){console.warn(`https://svelte.dev/e/hydration_mismatch`)}function be(){console.warn(`https://svelte.dev/e/select_multiple_invalid_value`)}function xe(){console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`)}var w=!1;function Se(e){w=e}var T;function E(e){if(e===null)throw ye(),ge;return T=e}function Ce(){return E(en(T))}function D(e){if(w){if(en(T)!==null)throw ye(),ge;T=e}}function we(e=1){if(w){for(var t=e,n=T;t--;)n=en(n);T=n}}function Te(e=!0){for(var t=0,n=T;;){if(n.nodeType===8){var r=n.data;if(r===`]`){if(t===0)return n;--t}else(r===`[`||r===`[!`||r[0]===`[`&&!isNaN(Number(r.slice(1))))&&(t+=1)}var i=en(n);e&&n.remove(),n=i}}function Ee(e){if(!e||e.nodeType!==8)throw ye(),ge;return e.data}function De(e){return e===this.v}function Oe(e,t){return e==e?e!==t||typeof e==`object`&&!!e||typeof e==`function`:t==t}function ke(e){return!Oe(e,this.v)}function Ae(e){throw Error(`https://svelte.dev/e/lifecycle_outside_component`)}function je(){throw Error(`https://svelte.dev/e/async_derived_orphan`)}function Me(e,t,n){throw Error(`https://svelte.dev/e/each_key_duplicate`)}function Ne(e){throw Error(`https://svelte.dev/e/effect_in_teardown`)}function Pe(){throw Error(`https://svelte.dev/e/effect_in_unowned_derived`)}function Fe(e){throw Error(`https://svelte.dev/e/effect_orphan`)}function Ie(){throw Error(`https://svelte.dev/e/effect_update_depth_exceeded`)}function Le(){throw Error(`https://svelte.dev/e/state_descriptors_fixed`)}function Re(){throw Error(`https://svelte.dev/e/state_prototype_fixed`)}function ze(){throw Error(`https://svelte.dev/e/state_unsafe_mutation`)}function Be(){throw Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`)}var O=null;function Ve(e){O=e}function He(e,t=!1,n){O={p:O,i:!1,c:null,e:null,s:e,x:null,r:G,l:null}}function Ue(e){var t=O,n=t.e;if(n!==null){t.e=null;for(var r of n)mn(r)}return e!==void 0&&(t.x=e),t.i=!0,O=t.p,We(e)}function We(e={}){return i(e,se,{value:!0}),e}function Ge(){return!0}var Ke=[];function qe(){var e=Ke;Ke=[],f(e)}function Je(e){if(Ke.length===0&&!bt){var t=Ke;queueMicrotask(()=>{t===Ke&&qe()})}Ke.push(e)}function Ye(){for(;Ke.length>0;)qe()}var Xe=~(g|_|h);function k(e,t){e.f=e.f&Xe|t}function Ze(e){e.f&512||e.deps===null?k(e,h):k(e,_)}function Qe(e,t,n){e.f&2048?t.add(e):e.f&4096&&n.add(e),k(e,h)}var $e=!1;function et(){$e||($e=!0,document.addEventListener(`reset`,e=>{Promise.resolve().then(()=>{if(!e.defaultPrevented)for(let t of e.target.elements)t[pe]?.()})},{capture:!0}))}function tt(e){var t=H,n=G;W(null),Pn(null);try{return e()}finally{W(t),Pn(n)}}function nt(e,t,n,r=n){e.addEventListener(t,()=>tt(n));let i=e[pe];e[pe]=i?()=>{i(),r(!0)}:()=>r(!0),et()}function rt(e,t,n,r){let i=Ge()?st:dt;var a=e.filter(e=>!e.settled),o=t.map(i);if(n.length===0&&a.length===0){r(o);return}var s=G,c=it(),l=a.length===1?a[0].promise:a.length>1?Promise.all(a.map(e=>e.promise)):null;function u(e){if(!(s.f&16384)){c();try{r([...o,...e])}catch(e){sn(e,s)}at()}}var d=ot();if(n.length===0){l.then(()=>u([])).finally(d);return}function f(){Promise.all(n.map(e=>lt(e))).then(u).catch(e=>sn(e,s)).finally(d)}l?l.then(()=>{c(),f(),at()}):f()}function it(){var e=G,t=H,n=O,r=A;return function(i=!0){Pn(e),W(t),Ve(n),i&&!(e.f&16384)&&(r?.activate(),r?.apply())}}function at(e=!0){Pn(null),W(null),Ve(null),e&&A?.deactivate()}function ot(){var e=G,t=e.b,n=A,r=!!t?.is_rendered();return t?.update_pending_count(1,n),n.increment(r,e),()=>{t?.update_pending_count(-1,n),n.decrement(r,e)}}function st(e){var t=2|g;return G!==null&&(G.f|=ee),{ctx:O,deps:null,effects:null,equals:De,f:t,fn:e,reactions:null,rv:0,v:C,wv:0,parent:G,ac:null}}var ct=Symbol(`obsolete`);function lt(e,t,n){let r=G;r===null&&je();var i=void 0,a=Lt(C),o=!H,s=new Set;return _n(()=>{var t=G,n=p();i=n.promise;try{Promise.resolve(e()).then(n.resolve,e=>{e!==me&&n.reject(e)}).finally(at)}catch(e){n.reject(e),at()}var c=A;if(o){if(t.f&32768)var l=ot();if(r.b?.is_rendered())c.async_deriveds.get(t)?.reject(ct);else for(let e of s.values())e.reject(ct);s.add(n),c.async_deriveds.set(t,n)}let u=(e,t=void 0)=>{l?.(),s.delete(n),t!==ct&&(c.activate(),t?(a.f|=ae,Vt(a,t)):(a.f&8388608&&(a.f^=ae),Vt(a,e)),c.deactivate())};n.promise.then(u,e=>u(null,e||`unknown`))}),fn(()=>{for(let e of s)e.reject(ct)}),new Promise(e=>{function t(n){function r(){n===i?e(a):t(i)}n.then(r,r)}t(i)})}function ut(e){let t=st(e);return In(t),t}function dt(e){let t=st(e);return t.equals=ke,t}function ft(e){var t=e.effects;if(t!==null){e.effects=null;for(var n=0;n{t.ac.abort(me),t.ac=null}),t.fn!==null&&(t.teardown=d),Jn(t,0),xn(t))}function gt(e){if(e.effects!==null)for(let t of e.effects)t.teardown&&t.fn!==null&&Yn(t)}var _t=null,A=null,vt=null,j=null,yt=null,bt=!1,xt=!1,St=null,Ct=null,wt=0,Tt=1,Et=class e{id=Tt++;#e=!1;linked=!0;#t=null;#n=null;async_deriveds=new Map;current=new Map;previous=new Map;#r=new Set;#i=new Set;#a=0;#o=new Map;#s=null;#c=[];#l=[];#u=new Set;#d=new Set;#f=new Map;#p=new Set;is_fork=!1;#m=!1;constructor(){_t===null?_t=this:(_t.#n=this,this.#t=_t),_t=this}#h(){if(this.is_fork)return!0;for(let n of this.#o.keys()){for(var e=n,t=!1;e.parent!==null;){if(this.#f.has(e)){t=!0;break}e=e.parent}if(!t)return!0}return!1}skip_effect(e){this.#f.has(e)||this.#f.set(e,{d:[],m:[]}),this.#p.delete(e)}unskip_effect(e,t=e=>this.schedule(e)){var n=this.#f.get(e);if(n){this.#f.delete(e);for(var r of n.d)k(r,g),t(r);for(r of n.m)k(r,_),t(r)}this.#p.add(e)}#g(){var e=[];for(let i of this.#c)if(!(i.f&16384||!(i.f&6144))){for(var t=i,n=!1;t.parent!==null;){t=t.parent;var r=t.f;if(r&96){if(!(r&1024)){n=!0;break}t.f^=h}}n||e.push(t)}return this.#c=[],e}#_(){this.#e=!0;for(let e of this.#u)this.#d.delete(e),k(e,g),this.schedule(e);for(let e of this.#d)k(e,_),this.schedule(e);this.apply();for(var t=St=[],n=[],r=Ct=[];this.#c.length>0;){wt++>1e3&&(this.#S(),Ot());for(let e of this.#g())try{this.#v(e,t,n)}catch(t){throw Nt(e),this.#h()||this.discard(),t}}if(A=null,r.length>0){var i=e.ensure();for(let e of r)i.schedule(e)}if(St=null,Ct=null,this.#h()){this.#x(n),this.#x(t);for(let[e,t]of this.#f)Mt(e,t);r.length>0&&A.#_();return}let a=this.#y();if(a)this.#x(n),this.#x(t),a.#b(this);else{this.#u.clear(),this.#d.clear();for(let e of this.#r)e(this);this.#r.clear(),vt=this,At(n),At(t),vt=null,this.#s?.resolve();var o=A;if(this.#a===0&&(this.#c.length===0||o!==null)&&this.#S(),this.#c.length>0){if(o!==null){for(let e of this.#c)o.#c.push(e);this.#c=[]}else o=this}o!==null&&(Ft.clear(),o.#_())}}#v(e,t,n){e.f^=h;for(var r=e.first;r!==null;){var i=r.f,a=!!(i&96);if(!(a&&i&1024||i&8192||this.#f.has(r))&&r.fn!==null){a?r.f^=h:i&4?t.push(r):Un(r)&&(i&16&&this.#d.add(r),Yn(r));var o=r.first;if(o!==null){r=o;continue}}for(;r!==null;){var s=r.next;if(s!==null){r=s;break}r=r.parent}}}#y(){for(var e=this.#t;e!==null;){if(!e.is_fork){for(let[t,[,n]]of this.current)if(e.current.has(t)&&!n)return e}e=e.#t}return null}#b(e){for(let[t,n]of e.current)!this.previous.has(t)&&e.previous.has(t)&&this.previous.set(t,e.previous.get(t)),this.current.set(t,n);for(let[t,n]of e.async_deriveds){let e=this.async_deriveds.get(t);e&&n.promise.then(e.resolve).catch(e.reject)}e.async_deriveds.clear(),this.transfer_effects(e.#u,e.#d);let t=e=>{var n=e.reactions;if(n!==null&&!(e.f&2&&!(e.f&6144)))for(let e of n){var r=e.f;if(r&2)t(e);else{var i=e;r&4194320&&!this.async_deriveds.has(i)&&(this.#d.delete(i),k(i,g),this.schedule(i))}}};for(let e of this.current.keys())t(e);this.oncommit(()=>e.discard()),e.#S(),A=this,this.#_()}#x(e){for(var t=0;t{this.#m=!1,this.linked&&this.flush()}))}transfer_effects(e,t){for(let t of e)this.#u.add(t);for(let e of t)this.#d.add(e);e.clear(),t.clear()}oncommit(e){this.#r.add(e)}ondiscard(e){this.#i.add(e)}settled(){return(this.#s??=p()).promise}static ensure(){if(A===null){let t=A=new e;!xt&&!bt&&Je(()=>{t.#e||t.flush()})}return A}apply(){j=null}schedule(e){yt=e,e.b?.is_pending&&e.f&16777228&&!(e.f&32768)?e.b.defer_effect(e):this.#c.push(e)}#S(){if(this.linked){var e=this.#t,t=this.#n;e===null||(e.#n=t),t===null?_t=e:t.#t=e,this.linked=!1}}};function Dt(e){var t=bt;bt=!0;try{var n;for(e&&(A!==null&&!A.is_fork&&A.flush(),n=e());;){if(Ye(),A===null)return n;A.flush()}}finally{bt=t}}function Ot(){try{Ie()}catch(e){sn(e,yt)}}var kt=null;function At(e){var t=e.length;if(t!==0){for(var n=0;n0)){Ft.clear();for(let e of kt){if(e.f&24576)continue;let t=[e],n=e.parent;for(;n!==null;)kt.has(n)&&(kt.delete(n),t.push(n)),n=n.parent;for(let e=t.length-1;e>=0;e--){let n=t[e];n.f&24576||Yn(n)}}kt.clear()}}kt=null}}function jt(e){A.schedule(e)}function Mt(e,t){if(!(e.f&32&&e.f&1024)){e.f&2048?t.d.push(e):e.f&4096&&t.m.push(e),k(e,h);for(var n=e.first;n!==null;)Mt(n,t),n=n.next}}function Nt(e){k(e,h);for(var t=e.first;t!==null;)Nt(t),t=t.next}var Pt=new Set,Ft=new Map,It=!1;function Lt(e,t){return{f:0,v:e,reactions:null,equals:De,rv:0,wv:0}}function M(e,t){let n=Lt(e,t);return In(n),n}function Rt(e,t=!1,n=!0){let r=Lt(e);return t||(r.equals=ke),r}function N(e,t,n=!1){return H!==null&&(!U||H.f&131072)&&Ge()&&H.f&4325394&&(Fn===null||!Fn.has(e))&&ze(),Vt(e,n?Gt(t):t,Ct)}var zt=null,Bt=0;function Vt(e,t,n=null){if(!e.equals(t)){Mn?Ft.set(e,t):Ft.has(e)||Ft.set(e,e.v);var r=Et.ensure();if(r.capture(e,t),e.f&2){let t=e;e.f&2048&&pt(t),j===null&&Ze(t)}e.wv=Hn(),zt=null,Bt=0,Wt(e,g,n),zt=null,Ge()&&G!==null&&G.f&1024&&!(G.f&96)&&(J===null?Ln([e]):J.push(e)),!r.is_fork&&Pt.size>0&&!It&&Ht()}return t}function Ht(){It=!1;for(let e of Pt){e.f&1024&&k(e,_);let t;try{t=Un(e)}catch{t=!0}t&&Yn(e)}Pt.clear()}function Ut(e){N(e,e.v+1)}function Wt(e,t,n){var r=e.reactions;if(r!==null){var i=Ge(),a=r.length;if(Bt+=a,Bt>1e5&&zt===null&&(zt=new Set),zt!==null){if(zt.has(e))return;zt.add(e)}for(var o=0;o{if(Bn===d)return e();var t=H,n=Bn;W(null),Vn(d);var r=e();return W(t),Vn(n),r};return i&&r.set(`length`,M(t.length,u)),new Proxy(t,{defineProperty(e,t,n){`value`in n&&n.configurable!==!1&&n.enumerable!==!1&&n.writable!==!1||Le();var i=r.get(t);return i===void 0?f(()=>{var e=M(n.value,u);return r.set(t,e),e}):N(i,n.value,!0),!0},deleteProperty(e,t){var n=r.get(t);if(n===void 0){if(t in e){let e=f(()=>M(C,u));r.set(t,e),Ut(o)}}else N(n,C),Ut(o);return!0},get(e,n,i){if(n===oe)return t;var o=r.get(n),s=n in e;if(o===void 0&&(!s||a(e,n)?.writable)&&(o=f(()=>M(Gt(s?e[n]:C),u)),r.set(n,o)),o!==void 0){var c=Y(o);return c===C?void 0:c}return Reflect.get(e,n,i)},getOwnPropertyDescriptor(e,t){this.has?.(e,t);var n=Reflect.getOwnPropertyDescriptor(e,t),i=r.get(t);if(i!==void 0){var a=Y(i);if(a===C)return;if(n&&`value`in n)n.value=a;else return{enumerable:!0,configurable:!0,value:a,writable:!0}}return n},has(e,t){if(t===oe)return!0;var n=r.get(t),i=n!==void 0&&n.v!==C||Reflect.has(e,t);return(n!==void 0||G!==null&&(!i||a(e,t)?.writable))&&(n===void 0&&(n=f(()=>M(i?Gt(e[t]):C,u)),r.set(t,n)),Y(n)===C)?!1:i},set(e,t,n,s){var c=r.get(t),l=t in e;if(i&&t===`length`)for(var d=n;dM(C,u)),r.set(d+``,p)):N(p,C)}if(c===void 0)(!l||a(e,t)?.writable)&&(c=f(()=>M(void 0,u)),N(c,Gt(n)),r.set(t,c));else{l=c.v!==C;var m=f(()=>Gt(n));N(c,m)}var h=Reflect.getOwnPropertyDescriptor(e,t);if(h?.set&&h.set.call(s,n),!l){if(i&&typeof t==`string`){var g=r.get(`length`),_=Number(t);Number.isInteger(_)&&_>=g.v&&N(g,_+1)}Ut(o)}return!0},ownKeys(e){Y(o);var t=Reflect.ownKeys(e).filter(e=>{var t=r.get(e);return t===void 0||t.v!==C});for(var[n,i]of r)i.v!==C&&!(n in e)&&t.push(n);return t},setPrototypeOf(){Re()}})}function Kt(e){try{if(typeof e==`object`&&e&&oe in e)return e[oe]}catch{}return e}function qt(e,t){return Object.is(Kt(e),Kt(t))}var Jt,Yt,Xt,Zt;function Qt(){if(Jt===void 0){Jt=window,Yt=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,n=Text.prototype;Xt=a(t,`firstChild`).get,Zt=a(t,`nextSibling`).get,u(e)&&(e[ue]=void 0,e[le]=null,e[de]=void 0,e.__e=void 0),u(n)&&(n[fe]=void 0)}}function P(e=``){return document.createTextNode(e)}function $t(e){return Xt.call(e)}function en(e){return Zt.call(e)}function F(e,t){if(!w)return $t(e);var n=$t(T);if(n===null)n=T.appendChild(P());else if(t&&n.nodeType!==3){var r=P();return n?.before(r),E(r),r}return t&&an(n),E(n),n}function I(e,t=!1){if(!w){var n=$t(e);return n instanceof Comment&&n.data===``?en(n):n}if(t){if(T?.nodeType!==3){var r=P();return T?.before(r),E(r),r}an(T)}return T}function L(e,t=!1){if(!w)return $t(e);var n=F(e,t);return D(e),n}function R(e,t=1,n=!1){let r=w?T:e;for(var i;t--;)i=r,r=en(r);if(!w)return r;if(n){if(r?.nodeType!==3){var a=P();return r===null?i?.after(a):r.before(a),E(a),a}an(r)}return E(r),r}function tn(e){e.textContent=``}function nn(){return!1}function rn(e,t,n){return t==null||t===`http://www.w3.org/1999/xhtml`?n?document.createElement(e,{is:n}):document.createElement(e):n?document.createElementNS(t,e,{is:n}):document.createElementNS(t,e)}function an(e){if(e.nodeValue.length<65536)return;let t=e.nextSibling;for(;t!==null&&t.nodeType===3;)t.remove(),e.nodeValue+=t.nodeValue,t=e.nextSibling}function on(e){var t=G;if(t===null)return H.f|=ae,e;if(!(t.f&32768)&&!(t.f&4))throw e;sn(e,t)}function sn(e,t){if(!(t!==null&&t.f&16384)){for(;t!==null;){if(t.f&128&&!(t.f&33570816)){if(!(t.f&32768))throw e;try{t.b.error(e);return}catch(t){e=t}}t=t.parent}throw e}}function cn(e){G===null&&(H===null&&Fe(e),Pe()),Mn&&Ne(e)}function ln(e,t){var n=t.last;n===null?t.last=t.first=e:(n.next=e,e.prev=n,t.last=e)}function un(e,t){var n=G;n!==null&&n.f&8192&&(e|=v);var r={ctx:O,deps:null,nodes:null,f:e|g|512,first:null,fn:t,last:null,next:null,parent:n,b:n&&n.b,prev:null,teardown:null,wv:0,ac:null};A?.register_created_effect(r);var i=r;if(e&4)St===null?Et.ensure().schedule(r):St.push(r);else if(t!==null){try{Yn(r)}catch(e){throw V(r),e}i.deps===null&&i.teardown===null&&i.nodes===null&&i.first===i.last&&!(i.f&524288)&&(i=i.first,e&16&&e&65536&&i!==null&&(i.f|=S))}if(i!==null&&(i.parent=n,n!==null&&ln(i,n),H!==null&&H.f&2&&!(e&64))){var a=H;(a.effects??=[]).push(i)}return r}function dn(){return H!==null&&!U}function fn(e){let t=un(8,null);return k(t,h),t.teardown=e,t}function pn(e){cn(`$effect`);var t=G.f;if(!H&&t&32&&O!==null&&!O.i){var n=O;(n.e??=[]).push(e)}else return mn(e)}function mn(e){return un(4|te,e)}function hn(e){Et.ensure();let t=un(64|ee,e);return(e={})=>new Promise(n=>{e.outro?Tn(t,()=>{V(t),n(void 0)}):(V(t),n(void 0))})}function gn(e){return un(4,e)}function _n(e){return un(ie|ee,e)}function vn(e,t=0){return un(8|t,e)}function z(e,t=[],n=[],r=[]){rt(r,t,n,t=>{un(8,()=>{e(...t.map(Y))})})}function yn(e,t=0){return un(16|t,e)}function B(e){return un(32|ee,e)}function bn(e){var t=e.teardown;if(t!==null){let n=Mn,r=H;Nn(!0),W(null);try{t.call(null)}catch(t){sn(t,e.parent)}finally{Nn(n),W(r)}}}function xn(e,t=!1){var n=e.first;for(e.first=e.last=null;n!==null;){let e=n.ac;e!==null&&tt(()=>{e.abort(me)});var r=n.next;n.f&64?n.parent=null:V(n,t),n=r}}function Sn(e){for(var t=e.first;t!==null;){var n=t.next;t.f&32||V(t),t=n}}function V(e,t=!0){var n=!1;(t||e.f&262144)&&e.nodes!==null&&e.nodes.end!==null&&(Cn(e.nodes.start,e.nodes.end),n=!0),e.f|=x,xn(e,t&&!n),Jn(e,0);var r=e.nodes&&e.nodes.t;if(r!==null)for(let e of r)e.stop();bn(e),e.f^=x,e.f|=y;var i=e.parent;i!==null&&i.first!==null&&wn(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=e.b=null}function Cn(e,t){for(;e!==null;){var n=e===t?null:en(e);e.remove(),e=n}}function wn(e){var t=e.parent,n=e.prev,r=e.next;n!==null&&(n.next=r),r!==null&&(r.prev=n),t!==null&&(t.first===e&&(t.first=r),t.last===e&&(t.last=n))}function Tn(e,t,n=!0){var r=[];e.f|=256,En(e,r,!0);var i=()=>{n&&V(e),t&&t()},a=r.length;if(a>0){var o=()=>--a||i();for(var s of r)s.out(o)}else i()}function En(e,t,n){if(!(e.f&8192)){e.f^=v;var r=e.nodes&&e.nodes.t;if(r!==null)for(let e of r)(e.is_global||n)&&t.push(e);for(var i=e.first;i!==null;){var a=i.next;if(!(i.f&64)){var o=!!(i.f&65536)||!!(i.f&32)&&!!(e.f&16);En(i,t,o?n:!1)}i=a}}}function Dn(e){e.f&=-257,On(e,!0)}function On(e,t){if(!(e.f&256)&&e.f&8192){e.f^=v,e.f&1024||(k(e,g),Et.ensure().schedule(e));for(var n=e.first;n!==null;){var r=n.next,i=!!(n.f&65536)||!!(n.f&32);On(n,i?t:!1),n=r}var a=e.nodes&&e.nodes.t;if(a!==null)for(let e of a)(e.is_global||t)&&e.in()}}function kn(e,t){if(e.nodes)for(var n=e.nodes.start,r=e.nodes.end;n!==null;){var i=n===r?null:en(n);t.append(n),n=i}}var An=null,jn=!1,Mn=!1;function Nn(e){Mn=e}var H=null,U=!1;function W(e){H=e}var G=null;function Pn(e){G=e}var Fn=null;function In(e){H!==null&&(H.f&2097152||H.f&2)&&(Fn??=new Set).add(e)}var K=null,q=0,J=null;function Ln(e){J=e}var Rn=1,zn=0,Bn=zn;function Vn(e){Bn=e}function Hn(){return++Rn}function Un(e){var t=e.f;if(t&2048)return!0;if(t&4096){for(var n=e.deps,r=n.length,i=0;ie.wv)return!0}t&512&&j===null&&k(e,h)}return!1}function Wn(e,t,n=!0){var r=e.reactions;if(r!==null&&!(Fn!==null&&Fn.has(e)))for(var i=0;i{e.ac.abort(me)}),e.ac=null);try{e.f|=re;var u=e.fn,d=u();e.f|=b;var f=Kn(e);if(Ge()&&J!==null&&!U&&f!==null&&!(e.f&6146))for(var p=0;p0)for(t.length=q+K.length,r=0;r{s.ac.abort(me),s.ac=null,k(s,g)}),ht(s),Jn(s,0)}}function Jn(e,t){var n=e.deps;if(n!==null)for(var r=t;rn?.call(this,e))}return e.startsWith(`pointer`)||e.startsWith(`touch`)||e===`wheel`?(i.__removed=!1,Je(()=>{i.__removed||t.addEventListener(e,i,r)})):t.addEventListener(e,i,r),i}function or(e,t,n,r,i){var a={capture:r,passive:i},o=ar(e,t,n,a);(t===document.body||t===window||t===document||t instanceof HTMLMediaElement)&&fn(()=>{o.__removed=!0,t.removeEventListener(e,o,a)})}function sr(e,t,n){(t[nr]??={})[e]=n}function cr(e){for(var t=0;t{ur=!1,lr=null}));var s=0,c=lr===e&&e[nr];if(c){var l=a.indexOf(c);if(l!==-1&&(t===document||t===window)){e[nr]=t;return}var u=a.indexOf(t);if(u===-1)return;l<=u&&(s=l)}if(o=a[s]||e.target,o!==t){i(e,`currentTarget`,{configurable:!0,get(){return o||n}});var d=H,f=G;W(null),Pn(null);try{for(var p,m=[];o!==null&&o!==t;){try{var h=o[nr]?.[r];h==null||o.disabled&&e.target!==o||h.call(o,e)}catch(e){p?m.push(e):p=e}if(e.cancelBubble)break;s++,o=s{throw e});throw p}}finally{e[nr]=t,delete e.currentTarget,W(d),Pn(f)}}}var fr=globalThis?.window?.trustedTypes&&globalThis.window.trustedTypes.createPolicy(`svelte-trusted-html`,{createHTML:e=>e});function pr(e){return fr?.createHTML(e)??e}function mr(e){var t=rn(`template`);return t.innerHTML=pr(e.replaceAll(``,``)),t.content}function hr(e,t){var n=G;n.nodes===null&&(n.nodes={start:e,end:t,a:null,t:null})}function X(e,t){var n=!!(t&1),r=!!(t&2),i,a=!e.startsWith(``);return()=>{if(w)return hr(T,null),T;i===void 0&&(i=mr(a?e:``+e),n||(i=$t(i)));var t=r||Yt?document.importNode(i,!0):i.cloneNode(!0);if(n){var o=$t(t),s=t.lastChild;hr(o,s)}else hr(t,t);return t}}function gr(e=``){if(!w){var t=P(e+``);return hr(t,t),t}var n=T;return n.nodeType===3?an(n):(n.before(n=P()),E(n)),hr(n,n),n}function _r(){if(w)return hr(T,null),T;var e=document.createDocumentFragment(),t=document.createComment(``),n=P();return e.append(t,n),hr(t,n),e}function Z(e,t){if(w){var n=G;n.f&32768&&n.nodes.end!==null||(n.nodes.end=T),Ce()}else e!==null&&e.before(t)}function vr(e){let t=0,n=Lt(0),r;return()=>{dn()&&(Y(n),vn(()=>(t===0&&(r=$n(()=>e(()=>Ut(n)))),t+=1,()=>{Je(()=>{--t,t===0&&(r?.(),r=void 0,Ut(n))})})))}}var yr=S|ee;function br(e,t,n,r){new xr(e,t,n,r)}var xr=class{parent;is_pending=!1;transform_error;#e;#t=w?T:null;#n;#r;#i;#a=null;#o=null;#s=null;#c=null;#l=0;#u=0;#d=!1;#f=new Set;#p=new Set;#m=null;#h=vr(()=>(this.#m=Lt(this.#l),()=>{this.#m=null}));constructor(e,t,n,r){this.#e=e,this.#n=t,this.#r=e=>{var t=G;t.b=this,t.f|=128,n(e)},this.parent=G.b,this.transform_error=r??this.parent?.transform_error??(e=>e),this.#i=yn(()=>{if(w){let e=this.#t;Ce();let t=e.data===`[!`;if(e.data.startsWith(`[?`)){let t=JSON.parse(e.data.slice(2));this.#_(t)}else t?this.#y():this.#g()}else this.#b()},yr),w&&(this.#e=T)}#g(){try{this.#a=B(()=>this.#r(this.#e))}catch(e){this.error(e)}}#_(e){let t=this.#n.failed,{reset:n,invoke_onerror:r}=this.#v(e);Je(r),t&&(this.#s=B(()=>{t(this.#e,()=>e,()=>n)}))}#v(e){var t=!1,n=!1;let r=()=>{t?xe():(t=!0,n&&Be(),this.#s!==null&&Tn(this.#s,()=>{this.#s=null}),this.#S(()=>{this.#b()}))};return{reset:r,invoke_onerror:()=>{try{n=!0,this.#n.onerror?.(e,r),n=!1}catch(e){sn(e,this.#i&&this.#i.parent)}}}}#y(){let e=this.#n.pending;e&&(this.is_pending=!0,this.#o=B(()=>e(this.#e)),Je(()=>{var e=this.#c=document.createDocumentFragment(),t=P(),n=!1;e.append(t),this.#a=this.#S(()=>{try{return B(()=>this.#r(t))}catch(e){try{this.error(e),n=!0}catch(e){sn(e,this.#i.parent)}return null}}),this.#a===null?(this.#c=null,n&&this.#x(A)):this.#u===0&&(this.#e.before(e),this.#c=null,Tn(this.#o,()=>{this.#o=null}),this.#x(A))}))}#b(){try{if(this.is_pending=this.has_pending_snippet(),this.#u=0,this.#l=0,this.#a=B(()=>{this.#r(this.#e)}),this.#u>0){var e=this.#c=document.createDocumentFragment();kn(this.#a,e);let t=this.#n.pending;this.#o=B(()=>t(this.#e))}else this.#x(A)}catch(e){this.error(e)}}#x(e){this.is_pending=!1,e.transfer_effects(this.#f,this.#p)}defer_effect(e){Qe(e,this.#f,this.#p)}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!this.#n.pending}#S(e){var t=G,n=H,r=O;Pn(this.#i),W(this.#i),Ve(this.#i.ctx);try{return Et.ensure(),e()}finally{Pn(t),W(n),Ve(r)}}#C(e,t){this.has_pending_snippet()?(this.#u+=e,this.#u===0&&(this.#x(t),this.#o&&Tn(this.#o,()=>{this.#o=null}),this.#c&&=(this.#e.before(this.#c),null))):this.parent&&this.parent.#C(e,t)}update_pending_count(e,t){this.#C(e,t),this.#l+=e,!(!this.#m||this.#d)&&(this.#d=!0,Je(()=>{this.#d=!1,this.#m&&Vt(this.#m,this.#l)}))}get_effect_pending(){return this.#h(),Y(this.#m)}error(e){if(!this.#n.onerror&&!this.#n.failed)throw e;A?.is_fork?(this.#a&&A.skip_effect(this.#a),this.#o&&A.skip_effect(this.#o),this.#s&&A.skip_effect(this.#s),A.oncommit(()=>{this.#w(e)})):this.#w(e)}#w(e){this.#a&&=(V(this.#a),null),this.#o&&=(V(this.#o),null),this.#s&&=(V(this.#s),null),w&&(E(this.#t),we(),E(Te()));let t=this.#n.failed,n=e=>{let{reset:n,invoke_onerror:r}=this.#v(e);r(),t&&(this.#s=this.#S(()=>{try{return B(()=>{var r=G;r.b=this,r.f|=128,t(this.#e,()=>e,()=>n)})}catch(e){return sn(e,this.#i.parent),null}}))};Je(()=>{var t;try{t=this.transform_error(e)}catch(e){sn(e,this.#i&&this.#i.parent);return}typeof t==`object`&&t&&typeof t.then==`function`?t.then(n,e=>sn(e,this.#i&&this.#i.parent)):n(t)})}};function Q(e,t){var n=t==null?``:typeof t==`object`?`${t}`:t;n!==(e[fe]??=e.nodeValue)&&(e[fe]=n,e.nodeValue=`${n}`)}function Sr(e,t){return wr(e,t)}var Cr=new Map;function wr(e,{target:t,anchor:n,props:i={},events:a,context:o,intro:s=!0,transformError:c}){Qt();var l=void 0,u=hn(()=>{var s=n??t.appendChild(P());br(s,{pending:()=>{}},t=>{He({});var n=O;if(o&&(n.c=o),a&&(i.$$events=a),w&&hr(t,null),l=e(t,i)||We(),w&&(G.nodes.end=T,T===null||T.nodeType!==8||T.data!==`]`))throw ye(),ge;Ue()},c);var u=new Set,d=e=>{for(var n=0;n{for(var e of u)for(let n of[t,document]){var r=Cr.get(n),i=r.get(e);--i==0?(n.removeEventListener(e,dr),r.delete(e),r.size===0&&Cr.delete(n)):r.set(e,i)}ir.delete(d),s!==n&&s.parentNode?.removeChild(s)}});return Tr.set(l,u),l}var Tr=new WeakMap,Er=class{anchor;#e=new Map;#t=new Map;#n=new Map;#r=new Set;#i=!0;constructor(e,t=!0){this.anchor=e,this.#i=t}#a=e=>{if(this.#e.has(e)){var t=this.#e.get(e),n=this.#t.get(t);if(n)Dn(n),this.#r.delete(t);else{var r=this.#n.get(t);r&&(Dn(r.effect),this.#t.set(t,r.effect),this.#n.delete(t),r.fragment.lastChild.remove(),this.anchor.before(r.fragment),n=r.effect)}for(let[t,n]of this.#e){if(this.#e.delete(t),t===e)break;let r=this.#n.get(n);r&&(V(r.effect),this.#n.delete(n))}for(let[e,r]of this.#t){if(e===t||this.#r.has(e))continue;let i=()=>{if(Array.from(this.#e.values()).includes(e)){var t=document.createDocumentFragment();kn(r,t),t.append(P()),this.#n.set(e,{effect:r,fragment:t})}else V(r);this.#r.delete(e),this.#t.delete(e)};this.#i||!n?(this.#r.add(e),Tn(r,i,!1)):i()}}};#o=e=>{this.#e.delete(e);let t=Array.from(this.#e.values());for(let[e,n]of this.#n)t.includes(e)||(V(n.effect),this.#n.delete(e))};ensure(e,t){var n=A,r=nn();if(t&&!this.#t.has(e)&&!this.#n.has(e)){if(r){var i=document.createDocumentFragment(),a=P();i.append(a),this.#n.set(e,{effect:B(()=>t(a)),fragment:i})}else this.#t.set(e,B(()=>t(this.anchor)))}if(this.#e.set(n,e),r){for(let[t,r]of this.#t)t===e?n.unskip_effect(r):n.skip_effect(r);for(let[t,r]of this.#n)t===e?n.unskip_effect(r.effect):n.skip_effect(r.effect);n.oncommit(this.#a),n.ondiscard(this.#o)}else w&&(this.anchor=T),this.#a(n)}};function $(e,t,n=!1){var r;w&&(r=T,Ce());var i=new Er(e),a=n?S:0;function o(e,t){if(w){var n=Ee(r);if(e!==parseInt(n.substring(1))){var a=Te();E(a),i.anchor=a,Se(!1),i.ensure(e,t),Se(!0);return}}i.ensure(e,t)}yn(()=>{var e=!1;t((t,n=0)=>{e=!0,o(n,t)}),e||o(-1,null)},a)}var Dr=Symbol(`NaN`);function Or(e,t,n){w&&Ce();var r=new Er(e),i=!Ge();yn(()=>{var e=t();e!==e&&(e=Dr),i&&typeof e==`object`&&e&&(e={}),r.ensure(e,n)})}function kr(e,t){return t}function Ar(e,t,n){for(var i=[],a=t.length,o,s=t.length,c=0;c{if(o){if(o.pending.delete(n),o.done.add(n),o.pending.size===0){var t=e.outrogroups;jr(e,r(o.done)),t.delete(o),t.size===0&&(e.outrogroups=null)}}else--s},!1)}if(s===0){var l=i.length===0&&n!==null&&e.pending.size===0;if(l){var u=n,d=u.parentNode;tn(d),d.append(u),e.items.clear()}jr(e,t,!l)}else o={pending:new Set(t),done:new Set},(e.outrogroups??=new Set).add(o)}function jr(e,t,n=!0){var r;if(e.pending.size>0){r=new Set;for(let t of e.pending.values())for(let n of t)r.add(e.items.get(n).e)}for(var i=0;i{var t=i();return e(t)?t:t==null?[]:r(t)}),p,m=new Map,h=!0;function g(e){v.effect.f&16384||(v.pending.delete(e),v.fallback=d,Fr(v,p,c,n,a),d!==null&&(p.length===0?d.f&33554432?(d.f^=ne,Lr(d,null,c)):Dn(d):Tn(d,()=>{d=null})))}function _(e){v.pending.delete(e)}var v={effect:yn(()=>{p=Y(f);var e=p.length;let t=!1;w&&Ee(c)===`[!`!=(e===0)&&(c=Te(),E(c),Se(!1),t=!0);for(var r=new Set,u=A,v=nn(),y=0;ys(c)):(d=B(()=>s(Mr??=P())),d.f|=ne)),e>r.size&&Me(``,``,``),w&&e>0&&E(Te()),!h){if(m.set(u,r),v){for(let[e,t]of l)r.has(e)||u.skip_effect(t.e);u.oncommit(g),u.ondiscard(_)}else g(u)}t&&Se(!0),Y(f)}),flags:n,items:l,pending:m,outrogroups:null,fallback:d};h=!1,w&&(c=T)}function Pr(e){for(;e!==null&&!(e.f&32);)e=e.next;return e}function Fr(e,t,n,i,a){var o=!!(i&8),s=t.length,c=e.items,l=Pr(e.effect.first),u,d=null,f,p=[],m=[],h,g,_,v;if(o)for(v=0;v0){var ie=i&4&&s===0?n:null;if(o){for(v=0;v{if(f!==void 0)for(_ of f)_.nodes?.a?.apply()})}function Ir(e,t,n,r,i,a,o,s){var c=o&1?o&16?Lt(n):Rt(n,!1,!1):null,l=o&2?Lt(i):null;return{v:c,i:l,e:B(()=>(a(t,c??n,l??i,s),()=>{e.delete(r)}))}}function Lr(e,t,n){if(e.nodes)for(var r=e.nodes.start,i=e.nodes.end,a=t&&!(t.f&33554432)?t.nodes.start:n;r!==null;){var o=en(r);if(a.before(r),r===i)return;r=o}}function Rr(e,t,n){t===null?e.effect.first=n:t.next=n,n===null?e.effect.last=t:n.prev=t}var zr=[...` -\r\f\xA0\v`];function Br(e,t,n){var r=e==null?``:``+e;if(t&&(r=r?r+` `+t:t),n){for(var i of Object.keys(n))if(n[i])r=r?r+` `+i:i;else if(r.length)for(var a=i.length,o=0;(o=r.indexOf(i,o))>=0;){var s=o+a;(o===0||zr.includes(r[o-1]))&&(s===r.length||zr.includes(r[s]))?r=(o===0?``:r.substring(0,o))+r.substring(s+1):o=s}}return r===``?null:r}function Vr(e,t,n,r,i,a){var o=e[ue];if(w||o!==n||o===void 0){var s=Br(n,r,a);w&&s===e.getAttribute(`class`)||(s==null?e.removeAttribute(`class`):t?e.className=s:e.setAttribute(`class`,s)),e[ue]=n}else if(a&&i!==a)for(var c in a){var l=!!a[c];(i==null||l!==!!i[c])&&e.classList.toggle(c,l)}return a}function Hr(e,t){t?e.hasAttribute(`selected`)||e.setAttribute(`selected`,``):e.removeAttribute(`selected`)}function Ur(t,n){var r=t.__defaultValue,i=t.multiple,a=i?r??[]:null;if(!i||e(a)){var o=t.selectedIndex,s=n&&i?new Set(t.selectedOptions):null;for(var c of t.options){var l=qr(c);Hr(c,i?a.includes(l):qt(l,r))}if(n){if(s!==null)for(c of t.options){var u=s.has(c);c.selected!==u&&(c.selected=u)}else t.selectedIndex!==o&&(t.selectedIndex=o)}}}function Wr(t,n,r=!1){if(t.multiple){if(n==null)return;if(!e(n))return be();for(var i of t.options)i.selected=n.includes(qr(i))}else{for(i of t.options)if(qt(qr(i),n)){i.selected=!0;return}r&&n===void 0||(t.selectedIndex=-1)}}function Gr(e){var t=new MutationObserver(t=>{t.every(Jr)||(`__defaultValue`in e&&Ur(e,!1),`__value`in e&&Wr(e,e.__value))});t.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[`value`]}),fn(()=>{t.disconnect()})}function Kr(e,t,n=t){var r=new WeakSet,i=!0;nt(e,`change`,t=>{var i=t?`[selected]`:`:checked`,a;if(e.multiple)a=[].map.call(e.querySelectorAll(i),qr);else{var o=e.querySelector(i)??e.querySelector(`option:not([disabled])`);a=o&&qr(o)}n(a),e.__value=a,A!==null&&r.add(A)}),gn(()=>{var a=t();if(e===document.activeElement){var o=A;if(r.has(o))return}if(Wr(e,a,i),i&&a===void 0){var s=e.querySelector(`:checked`);s!==null&&(a=qr(s),n(a))}e.__value=a,i=!1})}function qr(e){return`__value`in e?e.__value:e.value}function Jr(e){if(e.target.closest(`selectedcontent`)!==null)return!0;if(e.type===`childList`){var t=[...e.addedNodes,...e.removedNodes];return t.length>0&&t.every(e=>e.nodeName===`SELECTEDCONTENT`)}return!1}var Yr=Symbol(`is custom element`),Xr=Symbol(`is html`),Zr=he?`link`:`LINK`;function Qr(e){if(w){var t=!1,n=()=>{if(!t){if(t=!0,e.hasAttribute(`value`)){var n=e.value;$r(e,`value`,null),e.value=n}if(e.hasAttribute(`checked`)){var r=e.checked;$r(e,`checked`,null),e.checked=r}}};e[pe]=n,Je(n),et()}}function $r(e,t,n,r){var i=ei(e);w&&(i[t]=e.getAttribute(t),t===`src`||t===`srcset`||t===`href`&&e.nodeName===Zr)||i[t]!==(i[t]=n)&&(t===`loading`&&(e[ce]=n),n==null?e.removeAttribute(t):typeof n!=`string`&&ni(e).has(t)?e[t]=n:e.setAttribute(t,n))}function ei(e){return e[le]??={[Yr]:e.nodeName.includes(`-`),[Xr]:e.namespaceURI===_e}}var ti=new Map;function ni(e){var t=e.getAttribute(`is`)||e.nodeName,n=ti.get(t);if(n)return n;ti.set(t,n=new Set);for(var r,i=e,a=Element.prototype;a!==i;){for(var s in r=o(i),r)r[s].set&&s!==`innerHTML`&&s!==`textContent`&&s!==`innerText`&&n.add(s);i=l(i)}return n}function ri(e,t,n=t){var r=new WeakSet;nt(e,`input`,async i=>{var a=i?e.defaultValue:e.value;if(a=ai(e)?oi(a):a,n(a),A!==null&&r.add(A),await Xn(),a!==(a=t())){var o=e.selectionStart,s=e.selectionEnd,c=e.value.length;if(e.value=a??``,s!==null){var l=e.value.length;o===s&&s===c&&l>c?(e.selectionStart=l,e.selectionEnd=l):(e.selectionStart=o,e.selectionEnd=Math.min(s,l))}}}),(w&&e.defaultValue!==e.value||$n(t)==null&&e.value)&&(n(ai(e)?oi(e.value):e.value),A!==null&&r.add(A)),vn(()=>{var n=t();if(e===document.activeElement){var i=A;if(r.has(i))return}ai(e)&&n===oi(e.value)||(e.type!==`date`||n||e.value)&&n!==e.value&&(e.value=n??``)})}function ii(e,t,n=t){nt(e,`change`,t=>{n(t?e.defaultChecked:e.checked)}),(w&&e.defaultChecked!==e.checked||$n(t)==null)&&n(e.checked),vn(()=>{e.checked=!!t()})}function ai(e){var t=e.type;return t===`number`||t===`range`}function oi(e){return e===``?null:+e}function si(e){O===null&&Ae(`onMount`),pn(()=>{let t=$n(e);if(typeof t==`function`)return t})}typeof window<`u`&&((window.__svelte??={}).v??=new Set).add(`5`);var ci=``,li=class extends Error{constructor(e,t){super(t),this.status=e}};async function ui(e,t,n){let r={Accept:`application/json`};e!==`GET`&&(r[`Content-Type`]=`application/json`,r[`X-Rowbit-Token`]=ci);let i=await fetch(t,{method:e,headers:r,credentials:`same-origin`,body:n===void 0?void 0:JSON.stringify(n)});if(i.status===401)throw window.location.assign(`/login`),new li(401,`Signed out`);let a=await i.json().catch(()=>({}));if(!i.ok)throw new li(i.status,a.error||`HTTP ${i.status}`);return a}async function di(){let e=await ui(`GET`,`/api/session`);return ci=e.token,e}var fi=(e={})=>ui(`GET`,`/api/changes?${new URLSearchParams(Object.entries(e).filter(([,e])=>e))}`),pi=(e,t=0)=>ui(`GET`,`/api/changes/${e}?offset=${t}`),mi=(e,t,n)=>ui(`POST`,`/api/changes/${e}/approve`,{review:t,rows:n}),hi=(e,t)=>ui(`POST`,`/api/changes/${e}/reject`,{reason:t}),gi=e=>ui(`POST`,`/api/changes/${e}/undo`,{}),_i=()=>ui(`GET`,`/api/verify`),vi=()=>ui(`GET`,`/api/deliveries`),yi=()=>ui(`POST`,`/api/logout`,{});function bi(e,t,n=`${t}s`){return`${e.toLocaleString(`en`)} ${e===1?t:n}`}function xi(e){let t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)} min ago`:t<86400?`${Math.round(t/3600)} h ago`:`${Math.round(t/86400)} d ago`}function Si(e){return new Date(e).toLocaleString()}var Ci={insert:`inserts`,update:`updates`,delete:`deletes`,ddl:`changes the schema`},wi=X(` `);function Ti(e,t){var n=wi(),r=L(n,!0);z(()=>{Vr(n,1,`state ${t.state??``}`),Q(r,t.state)}),Z(e,n)}var Ei=X(`-`),Di=X(`NULL`),Oi=X(` `),ki=X(` `),Ai=X(` `);function ji(e,t){He(t,!0);var n=_r(),r=I(n),i=e=>{Z(e,Ei())},a=e=>{Z(e,Di())},o=e=>{var n=Oi(),r=L(n,!0);z(()=>Q(r,t.value.text)),Z(e,n)},s=e=>{var n=ki(),r=L(n,!0);z(()=>Q(r,t.value.text)),Z(e,n)},c=e=>{var n=Ai(),r=L(n);z(()=>Q(r,`"${t.value.text??``}"`)),Z(e,n)};$(r,e=>{t.value==null?e(i):t.value.kind===`null`?e(a,1):t.value.kind===`number`?e(o,2):t.value.kind===`binary`?e(s,3):e(c,-1)}),Z(e,n),Ue()}var Mi=X(``),Ni=X(`

`),Pi=X(`

`),Fi=X(`

Runs this schema change, which can't be undone:

 
`,1),Ii=X(``,1),Li=X(`new`),Ri=X(` `),zi=X(`

`),Bi=X(`

in

RowColumnBeforeAfter
`,1),Vi=X(``),Hi=X(`

`,1),Ui=X(`
Restores every row as it was, unless one changed since.
`),Wi=X(` `),Gi=X(`

 

History

WhenEventStateByDetail
`,1),Ki=X(`

Back to the queue

`,1);function qi(e,t){He(t,!0);let n=M(null),r=M(``),i=M(!1),a=M(!1),o=M(``),s=M(``);async function c(e=0){try{N(n,await pi(t.id,e),!0),N(r,``)}catch(e){N(r,e.message,!0)}}pn(()=>{c()});async function l(e){N(i,!0);try{N(n,await e(),!0),N(r,``)}catch(e){N(r,e.message,!0)}finally{N(i,!1)}}let u=ut(()=>Y(n)?.preview?.total_rows??0),d=ut(()=>Y(n)?.preview?Y(u)===1?`Approve and apply 1 row`:`Approve and apply all ${Y(u).toLocaleString(`en`)} rows`:`Approve and run`),f=ut(()=>!Y(n)?.confirm_rows||Number(Y(o))===Y(u)),p=ut(()=>Y(n)?.preview?Math.floor(Y(n).preview.offset/50):0),m=ut(()=>Math.ceil(Y(u)/50));var h=Ki(),g=R(I(h),2),_=e=>{var t=Mi(),n=L(t,!0);z(()=>Q(n,Y(r))),Z(e,t)};$(g,e=>{Y(r)&&e(_)});var v=R(g,2),y=e=>{var t=Gi(),r=I(t),h=F(r),g=F(h),_=L(g);Ti(R(g,2),{get state(){return Y(n).state}}),D(h);var v=R(h,2),y=e=>{var t=Ni(),r=L(t,!0);z(()=>Q(r,Y(n).reason)),Z(e,t)};$(v,e=>{Y(n).reason&&e(y)});var b=R(v,2),x=e=>{var t=Pi(),r=L(t);z(()=>Q(r,`Shadow mode: ${Y(n).shadowed.would??``} (${Y(n).shadowed.by??``}). It was applied anyway.`)),Z(e,t)};$(b,e=>{Y(n).shadowed&&e(x)});var S=R(b,2),ee=L(S,!0),te=R(S,2),ne=e=>{var t=Fi(),r=L(R(I(t),2),!0);z(()=>Q(r,Y(n).ddl)),Z(e,t)},re=e=>{var t=Bi(),r=I(t),i=F(r),o=R(i),s=L(o,!0),l=R(o,2),d=L(l,!0),f=R(l,2),h=F(f);Qr(h),we(),D(f),D(r);var g=R(r,2),_=F(g),v=R(F(_));Nr(v,21,()=>Y(n).preview.rows,kr,(e,t)=>{var n=_r();Nr(I(n),17,()=>Y(t).cells.filter(e=>Y(a)||e.changed),kr,(e,n,r)=>{var i=Ri();Vr(i,1,``,null,{},{first:r===0});var a=F(i),o=F(a),s=e=>{var n=_r(),r=I(n),i=e=>{var n=_r();Nr(I(n),17,()=>Y(t).key,kr,(e,t,n)=>{var r=Ii(),i=I(r),a=e=>{Z(e,gr(`,`))};$(i,e=>{n>0&&e(a)}),ji(R(i),{get value(){return Y(t)}}),Z(e,r)}),Z(e,n)},a=e=>{Z(e,Li())};$(r,e=>{Y(t).key?e(i):e(a,-1)}),Z(e,n)};$(o,e=>{r===0&&e(s)}),D(a);var c=R(a),l=L(c,!0),u=R(c);let d;ji(F(u),{get value(){return Y(n).before}}),D(u);var f=R(u);let p;ji(F(f),{get value(){return Y(n).after}}),D(f),D(i),z(()=>{Q(l,Y(n).column),d=Vr(u,1,`before`,null,d,{same:!Y(n).changed}),p=Vr(f,1,`after`,null,p,{same:!Y(n).changed})}),Z(e,i)}),Z(e,n)}),D(v),D(_),D(g);var y=R(g,2),b=e=>{var t=zi(),r=F(t),i=R(r),a=R(i);D(t),z((e,t)=>{r.disabled=Y(p)===0,Q(i,` Rows ${Y(n).preview.offset+1} to ${e??``} of - ${t??``} `),a.disabled=Y(p)+1>=Y(m)},[()=>Math.min(Y(n).preview.offset+50,Y(u)),()=>Y(u).toLocaleString(`en`)]),sr(`click`,r,()=>c((Y(p)-1)*50)),sr(`click`,a,()=>c((Y(p)+1)*50)),Z(e,t)};$(y,e=>{Y(m)>1&&e(b)}),z(e=>{Q(i,`${Ci[Y(n).preview.kind]??``} `),Q(s,e),Q(d,Y(n).preview.table)},[()=>bi(Y(u),`row`)]),ii(h,()=>Y(a),e=>N(a,e)),Z(e,t)};$(te,e=>{Y(n).ddl?e(ne):Y(n).preview&&e(re,1)});var ie=R(te,2),ae=e=>{var t=Hi(),r=I(t),a=F(r),c=F(a),p=e=>{var t=Vi(),n=R(F(t));Qr(n),D(t),z(e=>$r(n,`placeholder`,e),[()=>String(Y(u))]),ri(n,()=>Y(o),e=>N(o,e)),Z(e,t)};$(c,e=>{Y(n).confirm_rows&&e(p)});var m=R(c,2),h=L(m,!0);D(a);var g=R(a,2),_=F(g);Qr(_);var v=R(_,2);D(g),D(r);var y=L(R(r,2));z(e=>{m.disabled=Y(i)||!Y(f),Q(h,Y(d)),v.disabled=Y(i),Q(y,`Approving covers review ${e??``}: exactly the rows above.`)},[()=>Y(n).review_hash?.slice(0,12)]),or(`submit`,a,e=>{e.preventDefault(),l(()=>mi(Y(n).id,Y(n).review_hash,Y(n).confirm_rows?Number(Y(o)):void 0))}),or(`submit`,g,e=>{e.preventDefault(),l(()=>hi(Y(n).id,Y(s)))}),ri(_,()=>Y(s),e=>N(s,e)),Z(e,t)};$(ie,e=>{Y(n).state===`held`&&e(ae)});var oe=R(ie,2),se=e=>{var t=Ui(),r=F(t);we(2),D(t),z(()=>r.disabled=Y(i)),sr(`click`,r,()=>l(()=>gi(Y(n).id))),Z(e,t)};$(oe,e=>{Y(n).undoable&&e(se)}),D(r);var ce=R(r,4),le=R(F(ce));Nr(le,21,()=>Y(n).history,e=>e.seq,(e,t)=>{var n=Wi(),r=F(n),i=L(r,!0),a=R(r),o=L(a,!0),s=R(a),c=L(s,!0),l=R(s),u=L(l,!0),d=L(R(l),!0);D(n),z(e=>{Q(i,e),Q(o,Y(t).event),Q(c,Y(t).to),Q(u,Y(t).actor),Q(d,Y(t).detail??``)},[()=>Si(Y(t).at_ms)]),Z(e,n)}),D(le),D(ce),z(()=>{Q(_,`#${Y(n).id??``} from ${Y(n).agent??``}`),Q(ee,Y(n).statement)}),Z(e,t)};$(v,e=>{Y(n)&&e(y)}),Z(e,h),Ue()}cr([`click`]);var Ji=X(`

`),Yi=X(`

Nothing sent yet.

`),Xi=X(` `),Zi=X(`
ChangeTargetStateTriesLast errorQueued
`),Qi=X(`

Notifications

Held changes announced to the targets in rowbit-server.yml. A notification that - can't be delivered never affects the change; it stays held here.

`,1);function $i(e,t){He(t,!0);let n=M(null),r=M(``);async function i(){try{N(n,(await vi()).deliveries,!0),N(r,``)}catch(e){N(r,e.message,!0)}}si(()=>{i();let e=setInterval(i,1e4);return()=>clearInterval(e)});var a=Qi(),o=R(I(a),4),s=e=>{var t=Ji(),n=L(t,!0);z(()=>Q(n,Y(r))),Z(e,t)};$(o,e=>{Y(r)&&e(s)});var c=R(o,2),l=e=>{Z(e,Yi())};$(c,e=>{Y(n)&&Y(n).length===0&&e(l)});var u=R(c,2),d=e=>{var t=Zi(),r=F(t),i=R(F(r));Nr(i,21,()=>Y(n),e=>e.id,(e,t)=>{var n=Xi(),r=F(n),i=F(r),a=L(i);D(r);var o=R(r),s=L(o,!0),c=R(o),l=F(c),u=L(l,!0);D(c);var d=R(c),f=L(d,!0),p=R(d),m=L(p,!0),h=L(R(p),!0);D(n),z(e=>{$r(i,`href`,`#/changes/${Y(t).change_id??``}`),Q(a,`#${Y(t).change_id??``}`),Q(s,Y(t).target),Vr(l,1,`state ${Y(t).state===`delivered`?`applied`:Y(t).state===`failed`?`failed`:`held`}`),Q(u,Y(t).state),Q(f,Y(t).attempts),Q(m,Y(t).last_error??``),Q(h,e)},[()=>xi(Y(t).created_at_ms)]),Z(e,n)}),D(i),D(r),D(t),Z(e,t)};$(u,e=>{Y(n)&&Y(n).length&&e(d)}),Z(e,a),Ue()}var ea=X(`

The audit log's hash chain checks out.

`),ta=X(``),na=X(``),ra=X(`

`),ia=X(` `),aa=X(` `),oa=X(`

Log

#StateAgentWhatDecided byReasonWhen
`,1);function sa(e,t){He(t,!0);let n=[``,`proposed`,`held`,`approved`,`applied`,`rejected`,`failed`,`undone`],r=Gt({state:``,agent:``,table:``}),i=M(Gt([])),a=M(null),o=M(``);async function s(){try{N(i,(await fi(r)).changes,!0),N(o,``)}catch(e){N(o,e.message,!0)}}si(async()=>{s(),N(a,await _i().catch(e=>({ok:!1,problem:e.message})),!0)});var c=oa(),l=R(I(c),2),u=e=>{var t=_r(),n=I(t),r=e=>{Z(e,ea())},i=e=>{var t=ta(),n=L(t);z(()=>Q(n,`The audit log doesn't check out: ${Y(a).problem??``}`)),Z(e,t)};$(n,e=>{Y(a).ok?e(r):e(i,-1)}),Z(e,t)};$(l,e=>{Y(a)&&e(u)});var d=R(l,2),f=F(d),p=R(F(f));Nr(p,20,()=>n,e=>e,(e,t)=>{var n=na(),r=L(n,!0),i={};z(()=>{Q(r,t||`any`),i!==(i=t)&&(n.value=(n.__value=i)??``)}),Z(e,n)}),D(p),Gr(p),D(f);var m=R(f,2),h=R(F(m));Qr(h),D(m);var g=R(m,2),_=R(F(g));Qr(_),D(g),we(2),D(d);var v=R(d,2),y=e=>{var t=ra(),n=L(t,!0);z(()=>Q(n,Y(o))),Z(e,t)};$(v,e=>{Y(o)&&e(y)});var b=R(v,2),x=F(b),S=R(F(x));Nr(S,21,()=>Y(i),e=>e.id,(e,t)=>{var n=aa(),r=F(n),i=F(r),a=L(i,!0);D(r);var o=R(r);Ti(F(o),{get state(){return Y(t).state}}),D(o);var s=R(o),c=L(s,!0),l=R(s),u=F(l),d=R(u),f=e=>{var n=gr();z(()=>Q(n,Y(t).rows)),Z(e,n)};$(d,e=>{Y(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=ia(),r=L(n,!0);z(()=>Q(r,Y(t).table)),Z(e,n)};$(p,e=>{Y(t).table&&e(m)}),D(l);var h=R(l),g=L(h,!0),_=R(h),v=L(_,!0),y=L(R(_),!0);D(n),z(e=>{$r(i,`href`,`#/changes/${Y(t).id??``}`),Q(a,Y(t).id),Q(c,Y(t).agent),Q(u,`${Ci[Y(t).kind]??``??``} `),Q(g,Y(t).decided_by??``),Q(v,Y(t).reason??``),Q(y,e)},[()=>xi(Y(t).created_at_ms)]),Z(e,n)}),D(S),D(x),D(b),or(`submit`,d,e=>{e.preventDefault(),s()}),Kr(p,()=>r.state,e=>r.state=e),ri(h,()=>r.agent,e=>r.agent=e),ri(_,()=>r.table,e=>r.table=e),Z(e,c),Ue()}var ca=X(`

`),la=X(`

Nothing is waiting.

`),ua=X(` in`,1),da=X(` `),fa=X(`
`),pa=X(`
`),ma=X(`

Waiting for a person

`,1);function ha(e,t){He(t,!0);let n=M(null),r=M(Gt([])),i=M(``);async function a(){try{let e=await fi({state:`held`});N(n,e.changes.reverse(),!0),N(r,e.interrupted,!0),N(i,``)}catch(e){N(i,e.message,!0)}}si(()=>{a();let e=setInterval(a,1e4);return()=>clearInterval(e)});var o=ma(),s=I(o),c=R(F(s)),l=e=>{var t=gr();z(()=>Q(t,`(${Y(n).length??``})`)),Z(e,t)};$(c,e=>{Y(n)&&e(l)}),D(s);var u=R(s,2),d=e=>{var t=ca(),n=L(t);z(e=>Q(n,`Changes ${e??``} were interrupted while applying or undoing. Compare their rows - with the preview before anything else.`),[()=>Y(r).join(`, `)]),Z(e,t)};$(u,e=>{Y(r).length&&e(d)});var f=R(u,2),p=e=>{var t=ca(),n=L(t,!0);z(()=>Q(n,Y(i))),Z(e,t)};$(f,e=>{Y(i)&&e(p)});var m=R(f,2),h=e=>{Z(e,la())};$(m,e=>{Y(n)&&Y(n).length===0&&e(h)}),Nr(R(m,2),17,()=>Y(n)??[],e=>e.id,(e,t)=>{var n=pa(),r=F(n),i=F(r),a=L(i),o=R(i,2),s=L(o,!0),c=L(R(o,2),!0);D(r);var l=R(r,2),u=F(l),d=R(u),f=e=>{var n=ua(),r=L(I(n),!0);we(),z(e=>Q(r,e),[()=>bi(Y(t).rows,`row`)]),Z(e,n)};$(d,e=>{Y(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=da(),r=L(n,!0);z(()=>Q(r,Y(t).table)),Z(e,n)};$(p,e=>{Y(t).table&&e(m)}),D(l);var h=R(l,2),g=e=>{var n=fa(),r=L(n);z(()=>Q(r,`Held: ${Y(t).reason??``}`)),Z(e,n)};$(h,e=>{Y(t).reason&&e(g)}),D(n),z(e=>{$r(n,`href`,`#/changes/${Y(t).id??``}`),Q(a,`#${Y(t).id??``}`),Q(s,Y(t).agent),Q(c,e),Q(u,`${Ci[Y(t).kind]??`writes`??``} `)},[()=>xi(Y(t).created_at_ms)]),Z(e,n)}),Z(e,o),Ue()}var ga=X(`

`),_a=X(`

Nothing yet.

`),va=X(` `),ya=X(` `),ba=X(`

#StateAgentWhatWould haveWhen
`,1),xa=X(`

Shadow mode

Changes from agents in shadow mode that a rule would have held or blocked. They were applied, and - can be undone from their page.

`,1);function Sa(e,t){He(t,!0);let n=M(null),r=M(``);si(async()=>{try{let{changes:e}=await fi({shadowed:`true`}),t=new Map;for(let n of e){let e=n.shadowed.by;t.has(e)||t.set(e,[]),t.get(e).push(n)}N(n,[...t.entries()].sort((e,t)=>t[1].length-e[1].length),!0)}catch(e){N(r,e.message,!0)}});var i=xa(),a=R(I(i),4),o=e=>{var t=ga(),n=L(t,!0);z(()=>Q(n,Y(r))),Z(e,t)};$(a,e=>{Y(r)&&e(o)});var s=R(a,2),c=e=>{Z(e,_a())};$(s,e=>{Y(n)&&Y(n).length===0&&e(c)}),Nr(R(s,2),17,()=>Y(n)??[],([e,t])=>e,(e,t)=>{var n=ut(()=>m(Y(t),2));let r=()=>Y(n)[0],i=()=>Y(n)[1];var a=ba(),o=I(a),s=F(o),c=L(R(s));D(o);var l=R(o,2),u=F(l),d=R(F(u));Nr(d,21,i,e=>e.id,(e,t)=>{var n=ya(),r=F(n),i=F(r),a=L(i,!0);D(r);var o=R(r);Ti(F(o),{get state(){return Y(t).state}}),D(o);var s=R(o),c=L(s,!0),l=R(s),u=F(l),d=R(u),f=e=>{var n=gr();z(()=>Q(n,Y(t).rows)),Z(e,n)};$(d,e=>{Y(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=va(),r=L(n,!0);z(()=>Q(r,Y(t).table)),Z(e,n)};$(p,e=>{Y(t).table&&e(m)}),D(l);var h=R(l),g=L(h,!0),_=L(R(h),!0);D(n),z(e=>{$r(i,`href`,`#/changes/${Y(t).id??``}`),Q(a,Y(t).id),Q(c,Y(t).agent),Q(u,`${Ci[Y(t).kind]??``??``} `),Q(g,Y(t).shadowed.would??``),Q(_,e)},[()=>xi(Y(t).created_at_ms)]),Z(e,n)}),D(d),D(u),D(l),z(e=>{Q(s,`${r()??``} `),Q(c,`(${e??``})`)},[()=>bi(i().length,`change`)]),Z(e,a)}),Z(e,i),Ue()}var Ca=X(` `,1),wa=X(`

Loading...

`),Ta=X(`
Rowbit
`,1);function Ea(e,t){He(t,!0);let n=M(``),r=M(Gt(location.hash));si(()=>{di().then(e=>N(n,e.reviewer,!0));let e=()=>N(r,location.hash,!0);return addEventListener(`hashchange`,e),()=>removeEventListener(`hashchange`,e)});let i=ut(()=>Y(r).match(/^#\/changes\/(\d+)$/)?.[1]);async function a(){await yi().catch(()=>{}),location.assign(`/login`)}var o=Ta(),s=I(o),c=R(F(s),2),l=F(c);let u;var d=R(l,2);let f;var p=R(d,2);let m;var h=R(p,2);let g;D(c);var _=R(c,2),v=F(_),y=e=>{var t=Ca(),r=I(t),i=R(r);z(()=>Q(r,`${Y(n)??``} `)),sr(`click`,i,a),Z(e,t)};$(v,e=>{Y(n)&&e(y)}),D(_),D(s);var b=R(s,2),x=F(b),S=e=>{Z(e,wa())},ee=e=>{var t=_r();Or(I(t),()=>Y(i),e=>{qi(e,{get id(){return Y(i)}})}),Z(e,t)},te=e=>{sa(e,{})},ne=e=>{Sa(e,{})},re=e=>{$i(e,{})},ie=e=>{ha(e,{})};$(x,e=>{Y(n)?Y(i)?e(ee,1):Y(r)===`#/log`?e(te,2):Y(r)===`#/shadow`?e(ne,3):Y(r)===`#/notifications`?e(re,4):e(ie,-1):e(S)}),D(b),z(()=>{u=Vr(l,1,``,null,u,{active:Y(r)===``||Y(r)===`#/`}),f=Vr(d,1,``,null,f,{active:Y(r)===`#/log`}),m=Vr(p,1,``,null,m,{active:Y(r)===`#/shadow`}),g=Vr(h,1,``,null,g,{active:Y(r)===`#/notifications`})}),Z(e,o),Ue()}cr([`click`]),Sr(Ea,{target:document.getElementById(`app`)}); \ No newline at end of file +var e=Array.isArray,t=Array.prototype.indexOf,n=Array.prototype.includes,r=Array.from,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyDescriptors,s=Object.prototype,c=Array.prototype,l=Object.getPrototypeOf,u=Object.isExtensible,d=()=>{};function f(e){for(var t=0;t{e=n,t=r}),resolve:e,reject:t}}function m(e,t){if(Array.isArray(e))return e;if(t===void 0||!(Symbol.iterator in e))return Array.from(e);let n=[];for(let r of e)if(n.push(r),n.length===t)break;return n}var h=1024,g=2048,_=4096,v=8192,y=16384,b=32768,x=1<<25,S=65536,C=1<<19,ee=1<<20,te=1<<25,ne=1<<21,re=1<<22,ie=1<<23,ae=Symbol(`$state`),oe=Symbol(`component`),se=Symbol(``),ce=Symbol(`attributes`),le=Symbol(`class`),ue=Symbol(`style`),de=Symbol(`text`),fe=Symbol(`form reset`),pe=new class extends Error{name=`StaleReactionError`;message="The reaction that called `getAbortSignal()` was re-run or destroyed"},me=!!globalThis.document?.contentType&&globalThis.document.contentType.includes(`xml`),he={},w=Symbol(`uninitialized`),ge=`http://www.w3.org/1999/xhtml`;function _e(){console.warn(`https://svelte.dev/e/derived_inert`)}function ve(e){console.warn(`https://svelte.dev/e/hydration_mismatch`)}function ye(){console.warn(`https://svelte.dev/e/select_multiple_invalid_value`)}function be(){console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`)}var T=!1;function xe(e){T=e}var E;function D(e){if(e===null)throw ve(),he;return E=e}function Se(){return D(en(E))}function O(e){if(T){if(en(E)!==null)throw ve(),he;E=e}}function Ce(e=1){if(T){for(var t=e,n=E;t--;)n=en(n);E=n}}function we(e=!0){for(var t=0,n=E;;){if(n.nodeType===8){var r=n.data;if(r===`]`){if(t===0)return n;--t}else(r===`[`||r===`[!`||r[0]===`[`&&!isNaN(Number(r.slice(1))))&&(t+=1)}var i=en(n);e&&n.remove(),n=i}}function Te(e){if(!e||e.nodeType!==8)throw ve(),he;return e.data}function Ee(e){return e===this.v}function De(e,t){return e==e?e!==t||typeof e==`object`&&!!e||typeof e==`function`:t==t}function Oe(e){return!De(e,this.v)}function ke(e){throw Error(`https://svelte.dev/e/lifecycle_outside_component`)}function Ae(){throw Error(`https://svelte.dev/e/async_derived_orphan`)}function je(e,t,n){throw Error(`https://svelte.dev/e/each_key_duplicate`)}function Me(e){throw Error(`https://svelte.dev/e/effect_in_teardown`)}function Ne(){throw Error(`https://svelte.dev/e/effect_in_unowned_derived`)}function Pe(e){throw Error(`https://svelte.dev/e/effect_orphan`)}function Fe(){throw Error(`https://svelte.dev/e/effect_update_depth_exceeded`)}function Ie(){throw Error(`https://svelte.dev/e/state_descriptors_fixed`)}function Le(){throw Error(`https://svelte.dev/e/state_prototype_fixed`)}function Re(){throw Error(`https://svelte.dev/e/state_unsafe_mutation`)}function ze(){throw Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`)}var k=null;function Be(e){k=e}function Ve(e,t=!1,n){k={p:k,i:!1,c:null,e:null,s:e,x:null,r:W,l:null}}function He(e){var t=k,n=t.e;if(n!==null){t.e=null;for(var r of n)mn(r)}return e!==void 0&&(t.x=e),t.i=!0,k=t.p,Ue(e)}function Ue(e={}){return i(e,oe,{value:!0}),e}function We(){return!0}var Ge=[];function Ke(){var e=Ge;Ge=[],f(e)}function qe(e){if(Ge.length===0&&!bt){var t=Ge;queueMicrotask(()=>{t===Ge&&Ke()})}Ge.push(e)}function Je(){for(;Ge.length>0;)Ke()}var Ye=~(g|_|h);function A(e,t){e.f=e.f&Ye|t}function Xe(e){e.f&512||e.deps===null?A(e,h):A(e,_)}function Ze(e,t,n){e.f&2048?t.add(e):e.f&4096&&n.add(e),A(e,h)}var Qe=!1;function $e(){Qe||(Qe=!0,document.addEventListener(`reset`,e=>{Promise.resolve().then(()=>{if(!e.defaultPrevented)for(let t of e.target.elements)t[fe]?.()})},{capture:!0}))}function et(e){var t=H,n=W;U(null),Fn(null);try{return e()}finally{U(t),Fn(n)}}function tt(e,t,n,r=n){e.addEventListener(t,()=>et(n));let i=e[fe];e[fe]=i?()=>{i(),r(!0)}:()=>r(!0),$e()}function nt(e,t,n,r){let i=We()?ot:ut;var a=e.filter(e=>!e.settled),o=t.map(i);if(n.length===0&&a.length===0){r(o);return}var s=W,c=rt(),l=a.length===1?a[0].promise:a.length>1?Promise.all(a.map(e=>e.promise)):null;function u(e){if(!(s.f&16384)){c();try{r([...o,...e])}catch(e){sn(e,s)}it()}}var d=at();if(n.length===0){l.then(()=>u([])).finally(d);return}function f(){Promise.all(n.map(e=>ct(e))).then(u).catch(e=>sn(e,s)).finally(d)}l?l.then(()=>{c(),f(),it()}):f()}function rt(){var e=W,t=H,n=k,r=j;return function(i=!0){Fn(e),U(t),Be(n),i&&!(e.f&16384)&&(r?.activate(),r?.apply())}}function it(e=!0){Fn(null),U(null),Be(null),e&&j?.deactivate()}function at(){var e=W,t=e.b,n=j,r=!!t?.is_rendered();return t?.update_pending_count(1,n),n.increment(r,e),()=>{t?.update_pending_count(-1,n),n.decrement(r,e)}}function ot(e){var t=2|g;return W!==null&&(W.f|=C),{ctx:k,deps:null,effects:null,equals:Ee,f:t,fn:e,reactions:null,rv:0,v:w,wv:0,parent:W,ac:null}}var st=Symbol(`obsolete`);function ct(e,t,n){let r=W;r===null&&Ae();var i=void 0,a=Lt(w),o=!H,s=new Set;return _n(()=>{var t=W,n=p();i=n.promise;try{Promise.resolve(e()).then(n.resolve,e=>{e!==pe&&n.reject(e)}).finally(it)}catch(e){n.reject(e),it()}var c=j;if(o){if(t.f&32768)var l=at();if(r.b?.is_rendered())c.async_deriveds.get(t)?.reject(st);else for(let e of s.values())e.reject(st);s.add(n),c.async_deriveds.set(t,n)}let u=(e,t=void 0)=>{l?.(),s.delete(n),t!==st&&(c.activate(),t?(a.f|=ie,Vt(a,t)):(a.f&8388608&&(a.f^=ie),Vt(a,e)),c.deactivate())};n.promise.then(u,e=>u(null,e||`unknown`))}),fn(()=>{for(let e of s)e.reject(st)}),new Promise(e=>{function t(n){function r(){n===i?e(a):t(i)}n.then(r,r)}t(i)})}function lt(e){let t=ot(e);return Ln(t),t}function ut(e){let t=ot(e);return t.equals=Oe,t}function dt(e){var t=e.effects;if(t!==null){e.effects=null;for(var n=0;n{t.ac.abort(pe),t.ac=null}),t.fn!==null&&(t.teardown=d),Yn(t,0),xn(t))}function ht(e){if(e.effects!==null)for(let t of e.effects)t.teardown&&t.fn!==null&&Xn(t)}var gt=null,j=null,_t=null,vt=null,yt=null,bt=!1,xt=!1,St=null,Ct=null,wt=0,Tt=1,Et=class e{id=Tt++;#e=!1;linked=!0;#t=null;#n=null;async_deriveds=new Map;current=new Map;previous=new Map;#r=new Set;#i=new Set;#a=0;#o=new Map;#s=null;#c=[];#l=[];#u=new Set;#d=new Set;#f=new Map;#p=new Set;is_fork=!1;#m=!1;constructor(){gt===null?gt=this:(gt.#n=this,this.#t=gt),gt=this}#h(){if(this.is_fork)return!0;for(let n of this.#o.keys()){for(var e=n,t=!1;e.parent!==null;){if(this.#f.has(e)){t=!0;break}e=e.parent}if(!t)return!0}return!1}skip_effect(e){this.#f.has(e)||this.#f.set(e,{d:[],m:[]}),this.#p.delete(e)}unskip_effect(e,t=e=>this.schedule(e)){var n=this.#f.get(e);if(n){this.#f.delete(e);for(var r of n.d)A(r,g),t(r);for(r of n.m)A(r,_),t(r)}this.#p.add(e)}#g(){var e=[];for(let i of this.#c)if(!(i.f&16384||!(i.f&6144))){for(var t=i,n=!1;t.parent!==null;){t=t.parent;var r=t.f;if(r&96){if(!(r&1024)){n=!0;break}t.f^=h}}n||e.push(t)}return this.#c=[],e}#_(){this.#e=!0;for(let e of this.#u)this.#d.delete(e),A(e,g),this.schedule(e);for(let e of this.#d)A(e,_),this.schedule(e);this.apply();for(var t=St=[],n=[],r=Ct=[];this.#c.length>0;){wt++>1e3&&(this.#S(),Ot());for(let e of this.#g())try{this.#v(e,t,n)}catch(t){throw Nt(e),this.#h()||this.discard(),t}}if(j=null,r.length>0){var i=e.ensure();for(let e of r)i.schedule(e)}if(St=null,Ct=null,this.#h()){this.#x(n),this.#x(t);for(let[e,t]of this.#f)Mt(e,t);r.length>0&&j.#_();return}let a=this.#y();if(a)this.#x(n),this.#x(t),a.#b(this);else{this.#u.clear(),this.#d.clear();for(let e of this.#r)e(this);this.#r.clear(),_t=this,At(n),At(t),_t=null,this.#s?.resolve();var o=j;if(this.#a===0&&(this.#c.length===0||o!==null)&&this.#S(),this.#c.length>0){if(o!==null){for(let e of this.#c)o.#c.push(e);this.#c=[]}else o=this}o!==null&&(Ft.clear(),o.#_())}}#v(e,t,n){e.f^=h;for(var r=e.first;r!==null;){var i=r.f,a=!!(i&96);if(!(a&&i&1024||i&8192||this.#f.has(r))&&r.fn!==null){a?r.f^=h:i&4?t.push(r):Wn(r)&&(i&16&&this.#d.add(r),Xn(r));var o=r.first;if(o!==null){r=o;continue}}for(;r!==null;){var s=r.next;if(s!==null){r=s;break}r=r.parent}}}#y(){for(var e=this.#t;e!==null;){if(!e.is_fork){for(let[t,[,n]]of this.current)if(e.current.has(t)&&!n)return e}e=e.#t}return null}#b(e){for(let[t,n]of e.current)!this.previous.has(t)&&e.previous.has(t)&&this.previous.set(t,e.previous.get(t)),this.current.set(t,n);for(let[t,n]of e.async_deriveds){let e=this.async_deriveds.get(t);e&&n.promise.then(e.resolve).catch(e.reject)}e.async_deriveds.clear(),this.transfer_effects(e.#u,e.#d);let t=e=>{var n=e.reactions;if(n!==null&&!(e.f&2&&!(e.f&6144)))for(let e of n){var r=e.f;if(r&2)t(e);else{var i=e;r&4194320&&!this.async_deriveds.has(i)&&(this.#d.delete(i),A(i,g),this.schedule(i))}}};for(let e of this.current.keys())t(e);this.oncommit(()=>e.discard()),e.#S(),j=this,this.#_()}#x(e){for(var t=0;t{this.#m=!1,this.linked&&this.flush()}))}transfer_effects(e,t){for(let t of e)this.#u.add(t);for(let e of t)this.#d.add(e);e.clear(),t.clear()}oncommit(e){this.#r.add(e)}ondiscard(e){this.#i.add(e)}settled(){return(this.#s??=p()).promise}static ensure(){if(j===null){let t=j=new e;!xt&&!bt&&qe(()=>{t.#e||t.flush()})}return j}apply(){vt=null}schedule(e){yt=e,e.b?.is_pending&&e.f&16777228&&!(e.f&32768)?e.b.defer_effect(e):this.#c.push(e)}#S(){if(this.linked){var e=this.#t,t=this.#n;e===null||(e.#n=t),t===null?gt=e:t.#t=e,this.linked=!1}}};function Dt(e){var t=bt;bt=!0;try{var n;for(e&&(j!==null&&!j.is_fork&&j.flush(),n=e());;){if(Je(),j===null)return n;j.flush()}}finally{bt=t}}function Ot(){try{Fe()}catch(e){sn(e,yt)}}var kt=null;function At(e){var t=e.length;if(t!==0){for(var n=0;n0)){Ft.clear();for(let e of kt){if(e.f&24576)continue;let t=[e],n=e.parent;for(;n!==null;)kt.has(n)&&(kt.delete(n),t.push(n)),n=n.parent;for(let e=t.length-1;e>=0;e--){let n=t[e];n.f&24576||Xn(n)}}kt.clear()}}kt=null}}function jt(e){j.schedule(e)}function Mt(e,t){if(!(e.f&32&&e.f&1024)){e.f&2048?t.d.push(e):e.f&4096&&t.m.push(e),A(e,h);for(var n=e.first;n!==null;)Mt(n,t),n=n.next}}function Nt(e){A(e,h);for(var t=e.first;t!==null;)Nt(t),t=t.next}var Pt=new Set,Ft=new Map,It=!1;function Lt(e,t){return{f:0,v:e,reactions:null,equals:Ee,rv:0,wv:0}}function M(e,t){let n=Lt(e,t);return Ln(n),n}function Rt(e,t=!1,n=!0){let r=Lt(e);return t||(r.equals=Oe),r}function N(e,t,n=!1){return H!==null&&(!Pn||H.f&131072)&&We()&&H.f&4325394&&(In===null||!In.has(e))&&Re(),Vt(e,n?Gt(t):t,Ct)}var zt=null,Bt=0;function Vt(e,t,n=null){if(!e.equals(t)){Mn?Ft.set(e,t):Ft.has(e)||Ft.set(e,e.v);var r=Et.ensure();if(r.capture(e,t),e.f&2){let t=e;e.f&2048&&ft(t),vt===null&&Xe(t)}e.wv=Un(),zt=null,Bt=0,Wt(e,g,n),zt=null,We()&&W!==null&&W.f&1024&&!(W.f&96)&&(q===null?Rn([e]):q.push(e)),!r.is_fork&&Pt.size>0&&!It&&Ht()}return t}function Ht(){It=!1;for(let e of Pt){e.f&1024&&A(e,_);let t;try{t=Wn(e)}catch{t=!0}t&&Xn(e)}Pt.clear()}function Ut(e){N(e,e.v+1)}function Wt(e,t,n){var r=e.reactions;if(r!==null){var i=We(),a=r.length;if(Bt+=a,Bt>1e5&&zt===null&&(zt=new Set),zt!==null){if(zt.has(e))return;zt.add(e)}for(var o=0;o{if(Vn===d)return e();var t=H,n=Vn;U(null),Hn(d);var r=e();return U(t),Hn(n),r};return i&&r.set(`length`,M(t.length,u)),new Proxy(t,{defineProperty(e,t,n){`value`in n&&n.configurable!==!1&&n.enumerable!==!1&&n.writable!==!1||Ie();var i=r.get(t);return i===void 0?f(()=>{var e=M(n.value,u);return r.set(t,e),e}):N(i,n.value,!0),!0},deleteProperty(e,t){var n=r.get(t);if(n===void 0){if(t in e){let e=f(()=>M(w,u));r.set(t,e),Ut(o)}}else N(n,w),Ut(o);return!0},get(e,n,i){if(n===ae)return t;var o=r.get(n),s=n in e;if(o===void 0&&(!s||a(e,n)?.writable)&&(o=f(()=>M(Gt(s?e[n]:w),u)),r.set(n,o)),o!==void 0){var c=J(o);return c===w?void 0:c}return Reflect.get(e,n,i)},getOwnPropertyDescriptor(e,t){this.has?.(e,t);var n=Reflect.getOwnPropertyDescriptor(e,t),i=r.get(t);if(i!==void 0){var a=J(i);if(a===w)return;if(n&&`value`in n)n.value=a;else return{enumerable:!0,configurable:!0,value:a,writable:!0}}return n},has(e,t){if(t===ae)return!0;var n=r.get(t),i=n!==void 0&&n.v!==w||Reflect.has(e,t);return(n!==void 0||W!==null&&(!i||a(e,t)?.writable))&&(n===void 0&&(n=f(()=>M(i?Gt(e[t]):w,u)),r.set(t,n)),J(n)===w)?!1:i},set(e,t,n,s){var c=r.get(t),l=t in e;if(i&&t===`length`)for(var d=n;dM(w,u)),r.set(d+``,p)):N(p,w)}if(c===void 0)(!l||a(e,t)?.writable)&&(c=f(()=>M(void 0,u)),N(c,Gt(n)),r.set(t,c));else{l=c.v!==w;var m=f(()=>Gt(n));N(c,m)}var h=Reflect.getOwnPropertyDescriptor(e,t);if(h?.set&&h.set.call(s,n),!l){if(i&&typeof t==`string`){var g=r.get(`length`),_=Number(t);Number.isInteger(_)&&_>=g.v&&N(g,_+1)}Ut(o)}return!0},ownKeys(e){J(o);var t=Reflect.ownKeys(e).filter(e=>{var t=r.get(e);return t===void 0||t.v!==w});for(var[n,i]of r)i.v!==w&&!(n in e)&&t.push(n);return t},setPrototypeOf(){Le()}})}function Kt(e){try{if(typeof e==`object`&&e&&ae in e)return e[ae]}catch{}return e}function qt(e,t){return Object.is(Kt(e),Kt(t))}var Jt,Yt,Xt,Zt;function Qt(){if(Jt===void 0){Jt=window,Yt=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,n=Text.prototype;Xt=a(t,`firstChild`).get,Zt=a(t,`nextSibling`).get,u(e)&&(e[le]=void 0,e[ce]=null,e[ue]=void 0,e.__e=void 0),u(n)&&(n[de]=void 0)}}function P(e=``){return document.createTextNode(e)}function $t(e){return Xt.call(e)}function en(e){return Zt.call(e)}function F(e,t){if(!T)return $t(e);var n=$t(E);if(n===null)n=E.appendChild(P());else if(t&&n.nodeType!==3){var r=P();return n?.before(r),D(r),r}return t&&an(n),D(n),n}function I(e,t=!1){if(!T){var n=$t(e);return n instanceof Comment&&n.data===``?en(n):n}if(t){if(E?.nodeType!==3){var r=P();return E?.before(r),D(r),r}an(E)}return E}function L(e,t=!1){if(!T)return $t(e);var n=F(e,t);return O(e),n}function R(e,t=1,n=!1){let r=T?E:e;for(var i;t--;)i=r,r=en(r);if(!T)return r;if(n){if(r?.nodeType!==3){var a=P();return r===null?i?.after(a):r.before(a),D(a),a}an(r)}return D(r),r}function tn(e){e.textContent=``}function nn(){return!1}function rn(e,t,n){return t==null||t===`http://www.w3.org/1999/xhtml`?n?document.createElement(e,{is:n}):document.createElement(e):n?document.createElementNS(t,e,{is:n}):document.createElementNS(t,e)}function an(e){if(e.nodeValue.length<65536)return;let t=e.nextSibling;for(;t!==null&&t.nodeType===3;)t.remove(),e.nodeValue+=t.nodeValue,t=e.nextSibling}function on(e){var t=W;if(t===null)return H.f|=ie,e;if(!(t.f&32768)&&!(t.f&4))throw e;sn(e,t)}function sn(e,t){if(!(t!==null&&t.f&16384)){for(;t!==null;){if(t.f&128&&!(t.f&33570816)){if(!(t.f&32768))throw e;try{t.b.error(e);return}catch(t){e=t}}t=t.parent}throw e}}function cn(e){W===null&&(H===null&&Pe(e),Ne()),Mn&&Me(e)}function ln(e,t){var n=t.last;n===null?t.last=t.first=e:(n.next=e,e.prev=n,t.last=e)}function un(e,t){var n=W;n!==null&&n.f&8192&&(e|=v);var r={ctx:k,deps:null,nodes:null,f:e|g|512,first:null,fn:t,last:null,next:null,parent:n,b:n&&n.b,prev:null,teardown:null,wv:0,ac:null};j?.register_created_effect(r);var i=r;if(e&4)St===null?Et.ensure().schedule(r):St.push(r);else if(t!==null){try{Xn(r)}catch(e){throw V(r),e}i.deps===null&&i.teardown===null&&i.nodes===null&&i.first===i.last&&!(i.f&524288)&&(i=i.first,e&16&&e&65536&&i!==null&&(i.f|=S))}if(i!==null&&(i.parent=n,n!==null&&ln(i,n),H!==null&&H.f&2&&!(e&64))){var a=H;(a.effects??=[]).push(i)}return r}function dn(){return H!==null&&!Pn}function fn(e){let t=un(8,null);return A(t,h),t.teardown=e,t}function pn(e){cn(`$effect`);var t=W.f;if(!H&&t&32&&k!==null&&!k.i){var n=k;(n.e??=[]).push(e)}else return mn(e)}function mn(e){return un(4|ee,e)}function hn(e){Et.ensure();let t=un(64|C,e);return(e={})=>new Promise(n=>{e.outro?Tn(t,()=>{V(t),n(void 0)}):(V(t),n(void 0))})}function gn(e){return un(4,e)}function _n(e){return un(re|C,e)}function vn(e,t=0){return un(8|t,e)}function z(e,t=[],n=[],r=[]){nt(r,t,n,t=>{un(8,()=>{e(...t.map(J))})})}function yn(e,t=0){return un(16|t,e)}function B(e){return un(32|C,e)}function bn(e){var t=e.teardown;if(t!==null){let n=Mn,r=H;Nn(!0),U(null);try{t.call(null)}catch(t){sn(t,e.parent)}finally{Nn(n),U(r)}}}function xn(e,t=!1){var n=e.first;for(e.first=e.last=null;n!==null;){let e=n.ac;e!==null&&et(()=>{e.abort(pe)});var r=n.next;n.f&64?n.parent=null:V(n,t),n=r}}function Sn(e){for(var t=e.first;t!==null;){var n=t.next;t.f&32||V(t),t=n}}function V(e,t=!0){var n=!1;(t||e.f&262144)&&e.nodes!==null&&e.nodes.end!==null&&(Cn(e.nodes.start,e.nodes.end),n=!0),e.f|=x,xn(e,t&&!n),Yn(e,0);var r=e.nodes&&e.nodes.t;if(r!==null)for(let e of r)e.stop();bn(e),e.f^=x,e.f|=y;var i=e.parent;i!==null&&i.first!==null&&wn(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=e.b=null}function Cn(e,t){for(;e!==null;){var n=e===t?null:en(e);e.remove(),e=n}}function wn(e){var t=e.parent,n=e.prev,r=e.next;n!==null&&(n.next=r),r!==null&&(r.prev=n),t!==null&&(t.first===e&&(t.first=r),t.last===e&&(t.last=n))}function Tn(e,t,n=!0){var r=[];e.f|=256,En(e,r,!0);var i=()=>{n&&V(e),t&&t()},a=r.length;if(a>0){var o=()=>--a||i();for(var s of r)s.out(o)}else i()}function En(e,t,n){if(!(e.f&8192)){e.f^=v;var r=e.nodes&&e.nodes.t;if(r!==null)for(let e of r)(e.is_global||n)&&t.push(e);for(var i=e.first;i!==null;){var a=i.next;if(!(i.f&64)){var o=!!(i.f&65536)||!!(i.f&32)&&!!(e.f&16);En(i,t,o?n:!1)}i=a}}}function Dn(e){e.f&=-257,On(e,!0)}function On(e,t){if(!(e.f&256)&&e.f&8192){e.f^=v,e.f&1024||(A(e,g),Et.ensure().schedule(e));for(var n=e.first;n!==null;){var r=n.next,i=!!(n.f&65536)||!!(n.f&32);On(n,i?t:!1),n=r}var a=e.nodes&&e.nodes.t;if(a!==null)for(let e of a)(e.is_global||t)&&e.in()}}function kn(e,t){if(e.nodes)for(var n=e.nodes.start,r=e.nodes.end;n!==null;){var i=n===r?null:en(n);t.append(n),n=i}}var An=null,jn=!1,Mn=!1;function Nn(e){Mn=e}var H=null,Pn=!1;function U(e){H=e}var W=null;function Fn(e){W=e}var In=null;function Ln(e){H!==null&&(H.f&2097152||H.f&2)&&(In??=new Set).add(e)}var G=null,K=0,q=null;function Rn(e){q=e}var zn=1,Bn=0,Vn=Bn;function Hn(e){Vn=e}function Un(){return++zn}function Wn(e){var t=e.f;if(t&2048)return!0;if(t&4096){for(var n=e.deps,r=n.length,i=0;ie.wv)return!0}t&512&&vt===null&&A(e,h)}return!1}function Gn(e,t,n=!0){var r=e.reactions;if(r!==null&&!(In!==null&&In.has(e)))for(var i=0;i{e.ac.abort(pe)}),e.ac=null);try{e.f|=ne;var u=e.fn,d=u();e.f|=b;var f=qn(e);if(We()&&q!==null&&!Pn&&f!==null&&!(e.f&6146))for(var p=0;p0)for(t.length=K+G.length,r=0;r{s.ac.abort(pe),s.ac=null,A(s,g)}),mt(s),Yn(s,0)}}function Yn(e,t){var n=e.deps;if(n!==null)for(var r=t;rn?.call(this,e))}return e.startsWith(`pointer`)||e.startsWith(`touch`)||e===`wheel`?(i.__removed=!1,qe(()=>{i.__removed||t.addEventListener(e,i,r)})):t.addEventListener(e,i,r),i}function sr(e,t,n,r,i){var a={capture:r,passive:i},o=or(e,t,n,a);(t===document.body||t===window||t===document||t instanceof HTMLMediaElement)&&fn(()=>{o.__removed=!0,t.removeEventListener(e,o,a)})}function cr(e,t,n){(t[rr]??={})[e]=n}function lr(e){for(var t=0;t{dr=!1,ur=null}));var s=0,c=ur===e&&e[rr];if(c){var l=a.indexOf(c);if(l!==-1&&(t===document||t===window)){e[rr]=t;return}var u=a.indexOf(t);if(u===-1)return;l<=u&&(s=l)}if(o=a[s]||e.target,o!==t){i(e,`currentTarget`,{configurable:!0,get(){return o||n}});var d=H,f=W;U(null),Fn(null);try{for(var p,m=[];o!==null&&o!==t;){try{var h=o[rr]?.[r];h==null||o.disabled&&e.target!==o||h.call(o,e)}catch(e){p?m.push(e):p=e}if(e.cancelBubble)break;s++,o=s{throw e});throw p}}finally{e[rr]=t,delete e.currentTarget,U(d),Fn(f)}}}var pr=globalThis?.window?.trustedTypes&&globalThis.window.trustedTypes.createPolicy(`svelte-trusted-html`,{createHTML:e=>e});function mr(e){return pr?.createHTML(e)??e}function hr(e){var t=rn(`template`);return t.innerHTML=mr(e.replaceAll(``,``)),t.content}function gr(e,t){var n=W;n.nodes===null&&(n.nodes={start:e,end:t,a:null,t:null})}function Y(e,t){var n=!!(t&1),r=!!(t&2),i,a=!e.startsWith(``);return()=>{if(T)return gr(E,null),E;i===void 0&&(i=hr(a?e:``+e),n||(i=$t(i)));var t=r||Yt?document.importNode(i,!0):i.cloneNode(!0);if(n){var o=$t(t),s=t.lastChild;gr(o,s)}else gr(t,t);return t}}function _r(e=``){if(!T){var t=P(e+``);return gr(t,t),t}var n=E;return n.nodeType===3?an(n):(n.before(n=P()),D(n)),gr(n,n),n}function vr(){if(T)return gr(E,null),E;var e=document.createDocumentFragment(),t=document.createComment(``),n=P();return e.append(t,n),gr(t,n),e}function X(e,t){if(T){var n=W;n.f&32768&&n.nodes.end!==null||(n.nodes.end=E),Se()}else e!==null&&e.before(t)}function yr(e){let t=0,n=Lt(0),r;return()=>{dn()&&(J(n),vn(()=>(t===0&&(r=er(()=>e(()=>Ut(n)))),t+=1,()=>{qe(()=>{--t,t===0&&(r?.(),r=void 0,Ut(n))})})))}}var br=S|C;function xr(e,t,n,r){new Sr(e,t,n,r)}var Sr=class{parent;is_pending=!1;transform_error;#e;#t=T?E:null;#n;#r;#i;#a=null;#o=null;#s=null;#c=null;#l=0;#u=0;#d=!1;#f=new Set;#p=new Set;#m=null;#h=yr(()=>(this.#m=Lt(this.#l),()=>{this.#m=null}));constructor(e,t,n,r){this.#e=e,this.#n=t,this.#r=e=>{var t=W;t.b=this,t.f|=128,n(e)},this.parent=W.b,this.transform_error=r??this.parent?.transform_error??(e=>e),this.#i=yn(()=>{if(T){let e=this.#t;Se();let t=e.data===`[!`;if(e.data.startsWith(`[?`)){let t=JSON.parse(e.data.slice(2));this.#_(t)}else t?this.#y():this.#g()}else this.#b()},br),T&&(this.#e=E)}#g(){try{this.#a=B(()=>this.#r(this.#e))}catch(e){this.error(e)}}#_(e){let t=this.#n.failed,{reset:n,invoke_onerror:r}=this.#v(e);qe(r),t&&(this.#s=B(()=>{t(this.#e,()=>e,()=>n)}))}#v(e){var t=!1,n=!1;let r=()=>{t?be():(t=!0,n&&ze(),this.#s!==null&&Tn(this.#s,()=>{this.#s=null}),this.#S(()=>{this.#b()}))};return{reset:r,invoke_onerror:()=>{try{n=!0,this.#n.onerror?.(e,r),n=!1}catch(e){sn(e,this.#i&&this.#i.parent)}}}}#y(){let e=this.#n.pending;e&&(this.is_pending=!0,this.#o=B(()=>e(this.#e)),qe(()=>{var e=this.#c=document.createDocumentFragment(),t=P(),n=!1;e.append(t),this.#a=this.#S(()=>{try{return B(()=>this.#r(t))}catch(e){try{this.error(e),n=!0}catch(e){sn(e,this.#i.parent)}return null}}),this.#a===null?(this.#c=null,n&&this.#x(j)):this.#u===0&&(this.#e.before(e),this.#c=null,Tn(this.#o,()=>{this.#o=null}),this.#x(j))}))}#b(){try{if(this.is_pending=this.has_pending_snippet(),this.#u=0,this.#l=0,this.#a=B(()=>{this.#r(this.#e)}),this.#u>0){var e=this.#c=document.createDocumentFragment();kn(this.#a,e);let t=this.#n.pending;this.#o=B(()=>t(this.#e))}else this.#x(j)}catch(e){this.error(e)}}#x(e){this.is_pending=!1,e.transfer_effects(this.#f,this.#p)}defer_effect(e){Ze(e,this.#f,this.#p)}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!this.#n.pending}#S(e){var t=W,n=H,r=k;Fn(this.#i),U(this.#i),Be(this.#i.ctx);try{return Et.ensure(),e()}finally{Fn(t),U(n),Be(r)}}#C(e,t){this.has_pending_snippet()?(this.#u+=e,this.#u===0&&(this.#x(t),this.#o&&Tn(this.#o,()=>{this.#o=null}),this.#c&&=(this.#e.before(this.#c),null))):this.parent&&this.parent.#C(e,t)}update_pending_count(e,t){this.#C(e,t),this.#l+=e,!(!this.#m||this.#d)&&(this.#d=!0,qe(()=>{this.#d=!1,this.#m&&Vt(this.#m,this.#l)}))}get_effect_pending(){return this.#h(),J(this.#m)}error(e){if(!this.#n.onerror&&!this.#n.failed)throw e;j?.is_fork?(this.#a&&j.skip_effect(this.#a),this.#o&&j.skip_effect(this.#o),this.#s&&j.skip_effect(this.#s),j.oncommit(()=>{this.#w(e)})):this.#w(e)}#w(e){this.#a&&=(V(this.#a),null),this.#o&&=(V(this.#o),null),this.#s&&=(V(this.#s),null),T&&(D(this.#t),Ce(),D(we()));let t=this.#n.failed,n=e=>{let{reset:n,invoke_onerror:r}=this.#v(e);r(),t&&(this.#s=this.#S(()=>{try{return B(()=>{var r=W;r.b=this,r.f|=128,t(this.#e,()=>e,()=>n)})}catch(e){return sn(e,this.#i.parent),null}}))};qe(()=>{var t;try{t=this.transform_error(e)}catch(e){sn(e,this.#i&&this.#i.parent);return}typeof t==`object`&&t&&typeof t.then==`function`?t.then(n,e=>sn(e,this.#i&&this.#i.parent)):n(t)})}};function Z(e,t){var n=t==null?``:typeof t==`object`?`${t}`:t;n!==(e[de]??=e.nodeValue)&&(e[de]=n,e.nodeValue=`${n}`)}function Cr(e,t){return Tr(e,t)}var wr=new Map;function Tr(e,{target:t,anchor:n,props:i={},events:a,context:o,intro:s=!0,transformError:c}){Qt();var l=void 0,u=hn(()=>{var s=n??t.appendChild(P());xr(s,{pending:()=>{}},t=>{Ve({});var n=k;if(o&&(n.c=o),a&&(i.$$events=a),T&&gr(t,null),l=e(t,i)||Ue(),T&&(W.nodes.end=E,E===null||E.nodeType!==8||E.data!==`]`))throw ve(),he;He()},c);var u=new Set,d=e=>{for(var n=0;n{for(var e of u)for(let n of[t,document]){var r=wr.get(n),i=r.get(e);--i==0?(n.removeEventListener(e,fr),r.delete(e),r.size===0&&wr.delete(n)):r.set(e,i)}ar.delete(d),s!==n&&s.parentNode?.removeChild(s)}});return Er.set(l,u),l}var Er=new WeakMap,Dr=class{anchor;#e=new Map;#t=new Map;#n=new Map;#r=new Set;#i=!0;constructor(e,t=!0){this.anchor=e,this.#i=t}#a=e=>{if(this.#e.has(e)){var t=this.#e.get(e),n=this.#t.get(t);if(n)Dn(n),this.#r.delete(t);else{var r=this.#n.get(t);r&&(Dn(r.effect),this.#t.set(t,r.effect),this.#n.delete(t),r.fragment.lastChild.remove(),this.anchor.before(r.fragment),n=r.effect)}for(let[t,n]of this.#e){if(this.#e.delete(t),t===e)break;let r=this.#n.get(n);r&&(V(r.effect),this.#n.delete(n))}for(let[e,r]of this.#t){if(e===t||this.#r.has(e))continue;let i=()=>{if(Array.from(this.#e.values()).includes(e)){var t=document.createDocumentFragment();kn(r,t),t.append(P()),this.#n.set(e,{effect:r,fragment:t})}else V(r);this.#r.delete(e),this.#t.delete(e)};this.#i||!n?(this.#r.add(e),Tn(r,i,!1)):i()}}};#o=e=>{this.#e.delete(e);let t=Array.from(this.#e.values());for(let[e,n]of this.#n)t.includes(e)||(V(n.effect),this.#n.delete(e))};ensure(e,t){var n=j,r=nn();if(t&&!this.#t.has(e)&&!this.#n.has(e)){if(r){var i=document.createDocumentFragment(),a=P();i.append(a),this.#n.set(e,{effect:B(()=>t(a)),fragment:i})}else this.#t.set(e,B(()=>t(this.anchor)))}if(this.#e.set(n,e),r){for(let[t,r]of this.#t)t===e?n.unskip_effect(r):n.skip_effect(r);for(let[t,r]of this.#n)t===e?n.unskip_effect(r.effect):n.skip_effect(r.effect);n.oncommit(this.#a),n.ondiscard(this.#o)}else T&&(this.anchor=E),this.#a(n)}};function Q(e,t,n=!1){var r;T&&(r=E,Se());var i=new Dr(e),a=n?S:0;function o(e,t){if(T){var n=Te(r);if(e!==parseInt(n.substring(1))){var a=we();D(a),i.anchor=a,xe(!1),i.ensure(e,t),xe(!0);return}}i.ensure(e,t)}yn(()=>{var e=!1;t((t,n=0)=>{e=!0,o(n,t)}),e||o(-1,null)},a)}var Or=Symbol(`NaN`);function kr(e,t,n){T&&Se();var r=new Dr(e),i=!We();yn(()=>{var e=t();e!==e&&(e=Or),i&&typeof e==`object`&&e&&(e={}),r.ensure(e,n)})}function Ar(e,t){return t}function jr(e,t,n){for(var i=[],a=t.length,o,s=t.length,c=0;c{if(o){if(o.pending.delete(n),o.done.add(n),o.pending.size===0){var t=e.outrogroups;Mr(e,r(o.done)),t.delete(o),t.size===0&&(e.outrogroups=null)}}else--s},!1)}if(s===0){var l=i.length===0&&n!==null&&e.pending.size===0;if(l){var u=n,d=u.parentNode;tn(d),d.append(u),e.items.clear()}Mr(e,t,!l)}else o={pending:new Set(t),done:new Set},(e.outrogroups??=new Set).add(o)}function Mr(e,t,n=!0){var r;if(e.pending.size>0){r=new Set;for(let t of e.pending.values())for(let n of t)r.add(e.items.get(n).e)}for(var i=0;i{var t=i();return e(t)?t:t==null?[]:r(t)}),p,m=new Map,h=!0;function g(e){v.effect.f&16384||(v.pending.delete(e),v.fallback=d,Fr(v,p,c,n,a),d!==null&&(p.length===0?d.f&33554432?(d.f^=te,Lr(d,null,c)):Dn(d):Tn(d,()=>{d=null})))}function _(e){v.pending.delete(e)}var v={effect:yn(()=>{p=J(f);var e=p.length;let t=!1;T&&Te(c)===`[!`!=(e===0)&&(c=we(),D(c),xe(!1),t=!0);for(var r=new Set,u=j,v=nn(),y=0;ys(c)):(d=B(()=>s(Nr??=P())),d.f|=te)),e>r.size&&je(``,``,``),T&&e>0&&D(we()),!h){if(m.set(u,r),v){for(let[e,t]of l)r.has(e)||u.skip_effect(t.e);u.oncommit(g),u.ondiscard(_)}else g(u)}t&&xe(!0),J(f)}),flags:n,items:l,pending:m,outrogroups:null,fallback:d};h=!1,T&&(c=E)}function Pr(e){for(;e!==null&&!(e.f&32);)e=e.next;return e}function Fr(e,t,n,i,a){var o=!!(i&8),s=t.length,c=e.items,l=Pr(e.effect.first),u,d=null,f,p=[],m=[],h,g,_,v;if(o)for(v=0;v0){var re=i&4&&s===0?n:null;if(o){for(v=0;v{if(f!==void 0)for(_ of f)_.nodes?.a?.apply()})}function Ir(e,t,n,r,i,a,o,s){var c=o&1?o&16?Lt(n):Rt(n,!1,!1):null,l=o&2?Lt(i):null;return{v:c,i:l,e:B(()=>(a(t,c??n,l??i,s),()=>{e.delete(r)}))}}function Lr(e,t,n){if(e.nodes)for(var r=e.nodes.start,i=e.nodes.end,a=t&&!(t.f&33554432)?t.nodes.start:n;r!==null;){var o=en(r);if(a.before(r),r===i)return;r=o}}function Rr(e,t,n){t===null?e.effect.first=n:t.next=n,n===null?e.effect.last=t:n.prev=t}var zr=[...` +\r\f\xA0\v`];function Br(e,t,n){var r=e==null?``:``+e;if(t&&(r=r?r+` `+t:t),n){for(var i of Object.keys(n))if(n[i])r=r?r+` `+i:i;else if(r.length)for(var a=i.length,o=0;(o=r.indexOf(i,o))>=0;){var s=o+a;(o===0||zr.includes(r[o-1]))&&(s===r.length||zr.includes(r[s]))?r=(o===0?``:r.substring(0,o))+r.substring(s+1):o=s}}return r===``?null:r}function Vr(e,t,n,r,i,a){var o=e[le];if(T||o!==n||o===void 0){var s=Br(n,r,a);T&&s===e.getAttribute(`class`)||(s==null?e.removeAttribute(`class`):t?e.className=s:e.setAttribute(`class`,s)),e[le]=n}else if(a&&i!==a)for(var c in a){var l=!!a[c];(i==null||l!==!!i[c])&&e.classList.toggle(c,l)}return a}function Hr(e,t){t?e.hasAttribute(`selected`)||e.setAttribute(`selected`,``):e.removeAttribute(`selected`)}function Ur(t,n){var r=t.__defaultValue,i=t.multiple,a=i?r??[]:null;if(!i||e(a)){var o=t.selectedIndex,s=n&&i?new Set(t.selectedOptions):null;for(var c of t.options){var l=qr(c);Hr(c,i?a.includes(l):qt(l,r))}if(n){if(s!==null)for(c of t.options){var u=s.has(c);c.selected!==u&&(c.selected=u)}else t.selectedIndex!==o&&(t.selectedIndex=o)}}}function Wr(t,n,r=!1){if(t.multiple){if(n==null)return;if(!e(n))return ye();for(var i of t.options)i.selected=n.includes(qr(i))}else{for(i of t.options)if(qt(qr(i),n)){i.selected=!0;return}r&&n===void 0||(t.selectedIndex=-1)}}function Gr(e){var t=new MutationObserver(t=>{t.every(Jr)||(`__defaultValue`in e&&Ur(e,!1),`__value`in e&&Wr(e,e.__value))});t.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[`value`]}),fn(()=>{t.disconnect()})}function Kr(e,t,n=t){var r=new WeakSet,i=!0;tt(e,`change`,t=>{var i=t?`[selected]`:`:checked`,a;if(e.multiple)a=[].map.call(e.querySelectorAll(i),qr);else{var o=e.querySelector(i)??e.querySelector(`option:not([disabled])`);a=o&&qr(o)}n(a),e.__value=a,j!==null&&r.add(j)}),gn(()=>{var a=t();if(e===document.activeElement){var o=j;if(r.has(o))return}if(Wr(e,a,i),i&&a===void 0){var s=e.querySelector(`:checked`);s!==null&&(a=qr(s),n(a))}e.__value=a,i=!1})}function qr(e){return`__value`in e?e.__value:e.value}function Jr(e){if(e.target.closest(`selectedcontent`)!==null)return!0;if(e.type===`childList`){var t=[...e.addedNodes,...e.removedNodes];return t.length>0&&t.every(e=>e.nodeName===`SELECTEDCONTENT`)}return!1}var Yr=Symbol(`is custom element`),Xr=Symbol(`is html`),Zr=me?`link`:`LINK`;function Qr(e){if(T){var t=!1,n=()=>{if(!t){if(t=!0,e.hasAttribute(`value`)){var n=e.value;$r(e,`value`,null),e.value=n}if(e.hasAttribute(`checked`)){var r=e.checked;$r(e,`checked`,null),e.checked=r}}};e[fe]=n,qe(n),$e()}}function $r(e,t,n,r){var i=ei(e);T&&(i[t]=e.getAttribute(t),t===`src`||t===`srcset`||t===`href`&&e.nodeName===Zr)||i[t]!==(i[t]=n)&&(t===`loading`&&(e[se]=n),n==null?e.removeAttribute(t):typeof n!=`string`&&ni(e).has(t)?e[t]=n:e.setAttribute(t,n))}function ei(e){return e[ce]??={[Yr]:e.nodeName.includes(`-`),[Xr]:e.namespaceURI===ge}}var ti=new Map;function ni(e){var t=e.getAttribute(`is`)||e.nodeName,n=ti.get(t);if(n)return n;ti.set(t,n=new Set);for(var r,i=e,a=Element.prototype;a!==i;){for(var s in r=o(i),r)r[s].set&&s!==`innerHTML`&&s!==`textContent`&&s!==`innerText`&&n.add(s);i=l(i)}return n}function ri(e,t,n=t){var r=new WeakSet;tt(e,`input`,async i=>{var a=i?e.defaultValue:e.value;if(a=ai(e)?oi(a):a,n(a),j!==null&&r.add(j),await Zn(),a!==(a=t())){var o=e.selectionStart,s=e.selectionEnd,c=e.value.length;if(e.value=a??``,s!==null){var l=e.value.length;o===s&&s===c&&l>c?(e.selectionStart=l,e.selectionEnd=l):(e.selectionStart=o,e.selectionEnd=Math.min(s,l))}}}),(T&&e.defaultValue!==e.value||er(t)==null&&e.value)&&(n(ai(e)?oi(e.value):e.value),j!==null&&r.add(j)),vn(()=>{var n=t();if(e===document.activeElement){var i=j;if(r.has(i))return}ai(e)&&n===oi(e.value)||(e.type!==`date`||n||e.value)&&n!==e.value&&(e.value=n??``)})}function ii(e,t,n=t){tt(e,`change`,t=>{n(t?e.defaultChecked:e.checked)}),(T&&e.defaultChecked!==e.checked||er(t)==null)&&n(e.checked),vn(()=>{e.checked=!!t()})}function ai(e){var t=e.type;return t===`number`||t===`range`}function oi(e){return e===``?null:+e}function si(e){k===null&&ke(`onMount`),pn(()=>{let t=er(e);if(typeof t==`function`)return t})}typeof window<`u`&&((window.__svelte??={}).v??=new Set).add(`5`);var ci=``,li=class extends Error{constructor(e,t){super(t),this.status=e}};async function ui(e,t,n){let r={Accept:`application/json`};e!==`GET`&&(r[`Content-Type`]=`application/json`,r[`X-Rowbit-Token`]=ci);let i=await fetch(t,{method:e,headers:r,credentials:`same-origin`,body:n===void 0?void 0:JSON.stringify(n)});if(i.status===401)throw window.location.assign(`/login`),new li(401,`Signed out`);let a=await i.json().catch(()=>({}));if(!i.ok)throw new li(i.status,a.error||`HTTP ${i.status}`);return a}async function di(){let e=await ui(`GET`,`/api/session`);return ci=e.token,e}var fi=(e={})=>ui(`GET`,`/api/changes?${new URLSearchParams(Object.entries(e).filter(([,e])=>e))}`),pi=(e,t=0)=>ui(`GET`,`/api/changes/${e}?offset=${t}`),mi=(e,t,n)=>ui(`POST`,`/api/changes/${e}/approve`,{review:t,rows:n}),hi=(e,t)=>ui(`POST`,`/api/changes/${e}/reject`,{reason:t}),gi=e=>ui(`POST`,`/api/changes/${e}/undo`,{}),_i=()=>ui(`GET`,`/api/verify`),vi=()=>ui(`GET`,`/api/deliveries`),yi=()=>ui(`GET`,`/api/setup`),bi=()=>ui(`POST`,`/api/logout`,{});function xi(e,t,n=`${t}s`){return`${e.toLocaleString(`en`)} ${e===1?t:n}`}function Si(e){let t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)} min ago`:t<86400?`${Math.round(t/3600)} h ago`:`${Math.round(t/86400)} d ago`}function Ci(e){return new Date(e).toLocaleString()}var wi={insert:`inserts`,update:`updates`,delete:`deletes`,ddl:`changes the schema`},Ti=Y(` `);function Ei(e,t){var n=Ti(),r=L(n,!0);z(()=>{Vr(n,1,`state ${t.state??``}`),Z(r,t.state)}),X(e,n)}var Di=Y(`-`),Oi=Y(`NULL`),ki=Y(` `),Ai=Y(` `),ji=Y(` `);function Mi(e,t){Ve(t,!0);var n=vr(),r=I(n),i=e=>{X(e,Di())},a=e=>{X(e,Oi())},o=e=>{var n=ki(),r=L(n,!0);z(()=>Z(r,t.value.text)),X(e,n)},s=e=>{var n=Ai(),r=L(n,!0);z(()=>Z(r,t.value.text)),X(e,n)},c=e=>{var n=ji(),r=L(n);z(()=>Z(r,`"${t.value.text??``}"`)),X(e,n)};Q(r,e=>{t.value==null?e(i):t.value.kind===`null`?e(a,1):t.value.kind===`number`?e(o,2):t.value.kind===`binary`?e(s,3):e(c,-1)}),X(e,n),He()}var Ni=Y(``),Pi=Y(`

`),Fi=Y(`

`),Ii=Y(`

Runs this schema change, which can't be undone:

 
`,1),Li=Y(``,1),Ri=Y(`new`),zi=Y(` `),Bi=Y(`

`),Vi=Y(`

in

RowColumnBeforeAfter
`,1),Hi=Y(``),Ui=Y(`

`,1),Wi=Y(`
Restores every row as it was, unless one changed since.
`),Gi=Y(` `),Ki=Y(`

 

History

WhenEventStateByDetail
`,1),qi=Y(`

Back to the queue

`,1);function Ji(e,t){Ve(t,!0);let n=M(null),r=M(``),i=M(!1),a=M(!1),o=M(``),s=M(``);async function c(e=0){try{N(n,await pi(t.id,e),!0),N(r,``)}catch(e){N(r,e.message,!0)}}pn(()=>{c()});async function l(e){N(i,!0);try{N(n,await e(),!0),N(r,``)}catch(e){N(r,e.message,!0)}finally{N(i,!1)}}let u=lt(()=>J(n)?.preview?.total_rows??0),d=lt(()=>J(n)?.preview?J(u)===1?`Approve and apply 1 row`:`Approve and apply all ${J(u).toLocaleString(`en`)} rows`:`Approve and run`),f=lt(()=>!J(n)?.confirm_rows||Number(J(o))===J(u)),p=lt(()=>J(n)?.preview?Math.floor(J(n).preview.offset/50):0),m=lt(()=>Math.ceil(J(u)/50));var h=qi(),g=R(I(h),2),_=e=>{var t=Ni(),n=L(t,!0);z(()=>Z(n,J(r))),X(e,t)};Q(g,e=>{J(r)&&e(_)});var v=R(g,2),y=e=>{var t=Ki(),r=I(t),h=F(r),g=F(h),_=L(g);Ei(R(g,2),{get state(){return J(n).state}}),O(h);var v=R(h,2),y=e=>{var t=Pi(),r=L(t,!0);z(()=>Z(r,J(n).reason)),X(e,t)};Q(v,e=>{J(n).reason&&e(y)});var b=R(v,2),x=e=>{var t=Fi(),r=L(t);z(()=>Z(r,`Shadow mode: ${J(n).shadowed.would??``} (${J(n).shadowed.by??``}). It was applied anyway.`)),X(e,t)};Q(b,e=>{J(n).shadowed&&e(x)});var S=R(b,2),C=L(S,!0),ee=R(S,2),te=e=>{var t=Ii(),r=L(R(I(t),2),!0);z(()=>Z(r,J(n).ddl)),X(e,t)},ne=e=>{var t=Vi(),r=I(t),i=F(r),o=R(i),s=L(o,!0),l=R(o,2),d=L(l,!0),f=R(l,2),h=F(f);Qr(h),Ce(),O(f),O(r);var g=R(r,2),_=F(g),v=R(F(_));$(v,21,()=>J(n).preview.rows,Ar,(e,t)=>{var n=vr();$(I(n),17,()=>J(t).cells.filter(e=>J(a)||e.changed),Ar,(e,n,r)=>{var i=zi();Vr(i,1,``,null,{},{first:r===0});var a=F(i),o=F(a),s=e=>{var n=vr(),r=I(n),i=e=>{var n=vr();$(I(n),17,()=>J(t).key,Ar,(e,t,n)=>{var r=Li(),i=I(r),a=e=>{X(e,_r(`,`))};Q(i,e=>{n>0&&e(a)}),Mi(R(i),{get value(){return J(t)}}),X(e,r)}),X(e,n)},a=e=>{X(e,Ri())};Q(r,e=>{J(t).key?e(i):e(a,-1)}),X(e,n)};Q(o,e=>{r===0&&e(s)}),O(a);var c=R(a),l=L(c,!0),u=R(c);let d;Mi(F(u),{get value(){return J(n).before}}),O(u);var f=R(u);let p;Mi(F(f),{get value(){return J(n).after}}),O(f),O(i),z(()=>{Z(l,J(n).column),d=Vr(u,1,`before`,null,d,{same:!J(n).changed}),p=Vr(f,1,`after`,null,p,{same:!J(n).changed})}),X(e,i)}),X(e,n)}),O(v),O(_),O(g);var y=R(g,2),b=e=>{var t=Bi(),r=F(t),i=R(r),a=R(i);O(t),z((e,t)=>{r.disabled=J(p)===0,Z(i,` Rows ${J(n).preview.offset+1} to ${e??``} of + ${t??``} `),a.disabled=J(p)+1>=J(m)},[()=>Math.min(J(n).preview.offset+50,J(u)),()=>J(u).toLocaleString(`en`)]),cr(`click`,r,()=>c((J(p)-1)*50)),cr(`click`,a,()=>c((J(p)+1)*50)),X(e,t)};Q(y,e=>{J(m)>1&&e(b)}),z(e=>{Z(i,`${wi[J(n).preview.kind]??``} `),Z(s,e),Z(d,J(n).preview.table)},[()=>xi(J(u),`row`)]),ii(h,()=>J(a),e=>N(a,e)),X(e,t)};Q(ee,e=>{J(n).ddl?e(te):J(n).preview&&e(ne,1)});var re=R(ee,2),ie=e=>{var t=Ui(),r=I(t),a=F(r),c=F(a),p=e=>{var t=Hi(),n=R(F(t));Qr(n),O(t),z(e=>$r(n,`placeholder`,e),[()=>String(J(u))]),ri(n,()=>J(o),e=>N(o,e)),X(e,t)};Q(c,e=>{J(n).confirm_rows&&e(p)});var m=R(c,2),h=L(m,!0);O(a);var g=R(a,2),_=F(g);Qr(_);var v=R(_,2);O(g),O(r);var y=L(R(r,2));z(e=>{m.disabled=J(i)||!J(f),Z(h,J(d)),v.disabled=J(i),Z(y,`Approving covers review ${e??``}: exactly the rows above.`)},[()=>J(n).review_hash?.slice(0,12)]),sr(`submit`,a,e=>{e.preventDefault(),l(()=>mi(J(n).id,J(n).review_hash,J(n).confirm_rows?Number(J(o)):void 0))}),sr(`submit`,g,e=>{e.preventDefault(),l(()=>hi(J(n).id,J(s)))}),ri(_,()=>J(s),e=>N(s,e)),X(e,t)};Q(re,e=>{J(n).state===`held`&&e(ie)});var ae=R(re,2),oe=e=>{var t=Wi(),r=F(t);Ce(2),O(t),z(()=>r.disabled=J(i)),cr(`click`,r,()=>l(()=>gi(J(n).id))),X(e,t)};Q(ae,e=>{J(n).undoable&&e(oe)}),O(r);var se=R(r,4),ce=R(F(se));$(ce,21,()=>J(n).history,e=>e.seq,(e,t)=>{var n=Gi(),r=F(n),i=L(r,!0),a=R(r),o=L(a,!0),s=R(a),c=L(s,!0),l=R(s),u=L(l,!0),d=L(R(l),!0);O(n),z(e=>{Z(i,e),Z(o,J(t).event),Z(c,J(t).to),Z(u,J(t).actor),Z(d,J(t).detail??``)},[()=>Ci(J(t).at_ms)]),X(e,n)}),O(ce),O(se),z(()=>{Z(_,`#${J(n).id??``} from ${J(n).agent??``}`),Z(C,J(n).statement)}),X(e,t)};Q(v,e=>{J(n)&&e(y)}),X(e,h),He()}lr([`click`]);var Yi=Y(`

`),Xi=Y(`

Nothing sent yet.

`),Zi=Y(` `),Qi=Y(`
ChangeTargetStateTriesLast errorQueued
`),$i=Y(`

Notifications

Held changes announced to the targets in rowbit-server.yml. A notification that + can't be delivered never affects the change; it stays held here.

`,1);function ea(e,t){Ve(t,!0);let n=M(null),r=M(``);async function i(){try{N(n,(await vi()).deliveries,!0),N(r,``)}catch(e){N(r,e.message,!0)}}si(()=>{i();let e=setInterval(i,1e4);return()=>clearInterval(e)});var a=$i(),o=R(I(a),4),s=e=>{var t=Yi(),n=L(t,!0);z(()=>Z(n,J(r))),X(e,t)};Q(o,e=>{J(r)&&e(s)});var c=R(o,2),l=e=>{X(e,Xi())};Q(c,e=>{J(n)&&J(n).length===0&&e(l)});var u=R(c,2),d=e=>{var t=Qi(),r=F(t),i=R(F(r));$(i,21,()=>J(n),e=>e.id,(e,t)=>{var n=Zi(),r=F(n),i=F(r),a=L(i);O(r);var o=R(r),s=L(o,!0),c=R(o),l=F(c),u=L(l,!0);O(c);var d=R(c),f=L(d,!0),p=R(d),m=L(p,!0),h=L(R(p),!0);O(n),z(e=>{$r(i,`href`,`#/changes/${J(t).change_id??``}`),Z(a,`#${J(t).change_id??``}`),Z(s,J(t).target),Vr(l,1,`state ${J(t).state===`delivered`?`applied`:J(t).state===`failed`?`failed`:`held`}`),Z(u,J(t).state),Z(f,J(t).attempts),Z(m,J(t).last_error??``),Z(h,e)},[()=>Si(J(t).created_at_ms)]),X(e,n)}),O(i),O(r),O(t),X(e,t)};Q(u,e=>{J(n)&&J(n).length&&e(d)}),X(e,a),He()}var ta=Y(`

The audit log's hash chain checks out.

`),na=Y(``),ra=Y(``),ia=Y(`

`),aa=Y(` `),oa=Y(` `),sa=Y(`

Log

#StateAgentWhatDecided byReasonWhen
`,1);function ca(e,t){Ve(t,!0);let n=[``,`proposed`,`held`,`approved`,`applied`,`rejected`,`failed`,`undone`],r=Gt({state:``,agent:``,table:``}),i=M(Gt([])),a=M(null),o=M(``);async function s(){try{N(i,(await fi(r)).changes,!0),N(o,``)}catch(e){N(o,e.message,!0)}}si(async()=>{s(),N(a,await _i().catch(e=>({ok:!1,problem:e.message})),!0)});var c=sa(),l=R(I(c),2),u=e=>{var t=vr(),n=I(t),r=e=>{X(e,ta())},i=e=>{var t=na(),n=L(t);z(()=>Z(n,`The audit log doesn't check out: ${J(a).problem??``}`)),X(e,t)};Q(n,e=>{J(a).ok?e(r):e(i,-1)}),X(e,t)};Q(l,e=>{J(a)&&e(u)});var d=R(l,2),f=F(d),p=R(F(f));$(p,20,()=>n,e=>e,(e,t)=>{var n=ra(),r=L(n,!0),i={};z(()=>{Z(r,t||`any`),i!==(i=t)&&(n.value=(n.__value=i)??``)}),X(e,n)}),O(p),Gr(p),O(f);var m=R(f,2),h=R(F(m));Qr(h),O(m);var g=R(m,2),_=R(F(g));Qr(_),O(g),Ce(2),O(d);var v=R(d,2),y=e=>{var t=ia(),n=L(t,!0);z(()=>Z(n,J(o))),X(e,t)};Q(v,e=>{J(o)&&e(y)});var b=R(v,2),x=F(b),S=R(F(x));$(S,21,()=>J(i),e=>e.id,(e,t)=>{var n=oa(),r=F(n),i=F(r),a=L(i,!0);O(r);var o=R(r);Ei(F(o),{get state(){return J(t).state}}),O(o);var s=R(o),c=L(s,!0),l=R(s),u=F(l),d=R(u),f=e=>{var n=_r();z(()=>Z(n,J(t).rows)),X(e,n)};Q(d,e=>{J(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=aa(),r=L(n,!0);z(()=>Z(r,J(t).table)),X(e,n)};Q(p,e=>{J(t).table&&e(m)}),O(l);var h=R(l),g=L(h,!0),_=R(h),v=L(_,!0),y=L(R(_),!0);O(n),z(e=>{$r(i,`href`,`#/changes/${J(t).id??``}`),Z(a,J(t).id),Z(c,J(t).agent),Z(u,`${wi[J(t).kind]??``??``} `),Z(g,J(t).decided_by??``),Z(v,J(t).reason??``),Z(y,e)},[()=>Si(J(t).created_at_ms)]),X(e,n)}),O(S),O(x),O(b),sr(`submit`,d,e=>{e.preventDefault(),s()}),Kr(p,()=>r.state,e=>r.state=e),ri(h,()=>r.agent,e=>r.agent=e),ri(_,()=>r.table,e=>r.table=e),X(e,c),He()}var la=Y(`

`),ua=Y(`

Nothing is waiting.

`),da=Y(` in`,1),fa=Y(` `),pa=Y(`
`),ma=Y(`
`),ha=Y(`

Waiting for a person

`,1);function ga(e,t){Ve(t,!0);let n=M(null),r=M(Gt([])),i=M(``);async function a(){try{let e=await fi({state:`held`});N(n,e.changes.reverse(),!0),N(r,e.interrupted,!0),N(i,``)}catch(e){N(i,e.message,!0)}}si(()=>{a();let e=setInterval(a,1e4);return()=>clearInterval(e)});var o=ha(),s=I(o),c=R(F(s)),l=e=>{var t=_r();z(()=>Z(t,`(${J(n).length??``})`)),X(e,t)};Q(c,e=>{J(n)&&e(l)}),O(s);var u=R(s,2),d=e=>{var t=la(),n=L(t);z(e=>Z(n,`Changes ${e??``} were interrupted while applying or undoing. Compare their rows + with the preview before anything else.`),[()=>J(r).join(`, `)]),X(e,t)};Q(u,e=>{J(r).length&&e(d)});var f=R(u,2),p=e=>{var t=la(),n=L(t,!0);z(()=>Z(n,J(i))),X(e,t)};Q(f,e=>{J(i)&&e(p)});var m=R(f,2),h=e=>{X(e,ua())};Q(m,e=>{J(n)&&J(n).length===0&&e(h)}),$(R(m,2),17,()=>J(n)??[],e=>e.id,(e,t)=>{var n=ma(),r=F(n),i=F(r),a=L(i),o=R(i,2),s=L(o,!0),c=L(R(o,2),!0);O(r);var l=R(r,2),u=F(l),d=R(u),f=e=>{var n=da(),r=L(I(n),!0);Ce(),z(e=>Z(r,e),[()=>xi(J(t).rows,`row`)]),X(e,n)};Q(d,e=>{J(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=fa(),r=L(n,!0);z(()=>Z(r,J(t).table)),X(e,n)};Q(p,e=>{J(t).table&&e(m)}),O(l);var h=R(l,2),g=e=>{var n=pa(),r=L(n);z(()=>Z(r,`Held: ${J(t).reason??``}`)),X(e,n)};Q(h,e=>{J(t).reason&&e(g)}),O(n),z(e=>{$r(n,`href`,`#/changes/${J(t).id??``}`),Z(a,`#${J(t).id??``}`),Z(s,J(t).agent),Z(c,e),Z(u,`${wi[J(t).kind]??`writes`??``} `)},[()=>Si(J(t).created_at_ms)]),X(e,n)}),X(e,o),He()}var _a=Y(`

`),va=Y(`
Database
Server
(MariaDB or MySQL)
Rowbit connects as
Connection
`),ya=Y(`

Unknown: the database URL isn't available to the review page.

`),ba=Y(`
Files
`,1),xa=Y(`
Notifications
`,1),Sa=Y(`

`),Ca=Y(` `),wa=Y(`
ConnectedIdSinceLast used

Sign one out:

`,1),Ta=Y(`

Not connected over HTTP. Connect a client from your project: rowbit connect claude-code

`),Ea=Y(`

`,1),Da=Y(`

Database

Rowbit

Review page
Sign-in
Agents over HTTP
Held now
Version

Agents

`,1),Oa=Y(`

Setup

What this Rowbit guards, and where its agents are connected. Passwords are never shown. rowbit status shows the same for every setup on this machine.

`,1);function ka(e,t){Ve(t,!0);let n=M(null),r=M(``);async function i(){try{N(n,await yi(),!0),N(r,``)}catch(e){N(r,e.message,!0)}}si(()=>{i();let e=setInterval(i,15e3);return()=>clearInterval(e)});function a(e){let t={allow:`allows`,block:`refuses`}[e.default]??`holds`,n=e.rules===0?`${t} every write`:`${e.rules} rule${e.rules===1?``:`s`}, else ${t}`;return e.mode===`shadow`&&(n+=` (shadow mode: logged, not enforced)`),e.scoped&&(n+=`, scoped`),n}var o=Oa(),s=R(I(o),4),c=e=>{var t=_a(),n=L(t,!0);z(()=>Z(n,J(r))),X(e,t)};Q(s,e=>{J(r)&&e(c)});var l=R(s,2),u=e=>{var t=Da(),r=I(t),i=R(F(r),2),o=e=>{var t=va(),r=R(F(t)),i=L(F(r),!0);O(r);var a=R(r,3),o=L(F(a));Ce(),O(a);var s=R(a,3),c=L(F(s),!0);O(s);var l=L(R(s,3),!0);O(t),z(()=>{Z(i,J(n).database.database),Z(o,`${J(n).database.host??``}:${J(n).database.port??``}`),Z(c,J(n).database.user),Z(l,J(n).database.tls)}),X(e,t)},s=e=>{X(e,ya())};Q(i,e=>{J(n).database?e(o):e(s,-1)}),O(r);var c=R(r,2),l=R(F(c),2),u=F(l),d=e=>{var t=ba(),r=R(I(t)),i=L(F(r),!0);O(r),z(()=>Z(i,J(n).dir)),X(e,t)};Q(u,e=>{J(n).dir&&e(d)});var f=R(u,3),p=L(f,!0),m=R(f,3),h=L(m,!0),g=R(m,3),_=L(g,!0),v=R(g,2),y=e=>{var t=xa(),r=L(R(I(t)),!0);z(e=>Z(r,e),[()=>J(n).notify.join(`, `)]),X(e,t)};Q(v,e=>{J(n).notify?.length&&e(y)});var b=R(v,3),x=L(F(b),!0);O(b);var S=L(R(b,3),!0);O(l),O(c);var C=R(c,2);$(R(F(C),2),17,()=>J(n).agents,e=>e.id,(e,t)=>{var n=Ea(),r=I(n),i=L(F(r),!0);O(r);var o=R(r,2),s=e=>{var n=Sa(),r=L(n,!0);z(()=>Z(r,J(t).description)),X(e,n)};Q(o,e=>{J(t).description&&e(s)});var c=R(o,2),l=L(c,!0),u=R(c,2),d=e=>{var n=wa(),r=I(n),i=F(r),a=R(F(i));$(a,21,()=>J(t).connections,e=>e.id,(e,t)=>{var n=Ca(),r=F(n),i=L(r,!0),a=R(r),o=L(F(a),!0);O(a);var s=R(a),c=L(s,!0),l=L(R(s),!0);O(n),z((e,n)=>{Z(i,J(t).label),Z(o,J(t).id),Z(c,e),Z(l,n)},[()=>Si(J(t).created_ms),()=>J(t).used_ms?Si(J(t).used_ms):`never`]),X(e,n)}),O(a),O(i),O(r);var o=R(r,2),s=L(R(F(o)));O(o),z(()=>Z(s,`rowbit agents revoke ${J(t).id??``} --connection `)),X(e,n)},f=e=>{X(e,Ta())};Q(u,e=>{J(t).connections.length?e(d):e(f,-1)}),z(e=>{Z(i,J(t).id),Z(l,e)},[()=>a(J(t))]),X(e,n)}),O(C),z(()=>{Z(p,J(n).review_page),Z(h,J(n).sign_in),Z(_,J(n).mcp??`off (agents start rowbit mcp themselves)`),Z(x,J(n).held),Z(S,J(n).version)}),X(e,t)};Q(l,e=>{J(n)&&e(u)}),X(e,o),He()}var Aa=Y(`

`),ja=Y(`

Nothing yet.

`),Ma=Y(` `),Na=Y(` `),Pa=Y(`

#StateAgentWhatWould haveWhen
`,1),Fa=Y(`

Shadow mode

Changes from agents in shadow mode that a rule would have held or blocked. They were applied, and + can be undone from their page.

`,1);function Ia(e,t){Ve(t,!0);let n=M(null),r=M(``);si(async()=>{try{let{changes:e}=await fi({shadowed:`true`}),t=new Map;for(let n of e){let e=n.shadowed.by;t.has(e)||t.set(e,[]),t.get(e).push(n)}N(n,[...t.entries()].sort((e,t)=>t[1].length-e[1].length),!0)}catch(e){N(r,e.message,!0)}});var i=Fa(),a=R(I(i),4),o=e=>{var t=Aa(),n=L(t,!0);z(()=>Z(n,J(r))),X(e,t)};Q(a,e=>{J(r)&&e(o)});var s=R(a,2),c=e=>{X(e,ja())};Q(s,e=>{J(n)&&J(n).length===0&&e(c)}),$(R(s,2),17,()=>J(n)??[],([e,t])=>e,(e,t)=>{var n=lt(()=>m(J(t),2));let r=()=>J(n)[0],i=()=>J(n)[1];var a=Pa(),o=I(a),s=F(o),c=L(R(s));O(o);var l=R(o,2),u=F(l),d=R(F(u));$(d,21,i,e=>e.id,(e,t)=>{var n=Na(),r=F(n),i=F(r),a=L(i,!0);O(r);var o=R(r);Ei(F(o),{get state(){return J(t).state}}),O(o);var s=R(o),c=L(s,!0),l=R(s),u=F(l),d=R(u),f=e=>{var n=_r();z(()=>Z(n,J(t).rows)),X(e,n)};Q(d,e=>{J(t).rows!=null&&e(f)});var p=R(d,2),m=e=>{var n=Ma(),r=L(n,!0);z(()=>Z(r,J(t).table)),X(e,n)};Q(p,e=>{J(t).table&&e(m)}),O(l);var h=R(l),g=L(h,!0),_=L(R(h),!0);O(n),z(e=>{$r(i,`href`,`#/changes/${J(t).id??``}`),Z(a,J(t).id),Z(c,J(t).agent),Z(u,`${wi[J(t).kind]??``??``} `),Z(g,J(t).shadowed.would??``),Z(_,e)},[()=>Si(J(t).created_at_ms)]),X(e,n)}),O(d),O(u),O(l),z(e=>{Z(s,`${r()??``} `),Z(c,`(${e??``})`)},[()=>xi(i().length,`change`)]),X(e,a)}),X(e,i),He()}var La=Y(`Guarding on as `),Ra=Y(` `,1),za=Y(`

Loading...

`),Ba=Y(`
Rowbit
`,1);function Va(e,t){Ve(t,!0);let n=M(``),r=M(null),i=M(Gt(location.hash));si(()=>{di().then(e=>{N(n,e.reviewer,!0),yi().then(e=>N(r,e.database,!0)).catch(()=>{})});let e=()=>N(i,location.hash,!0);return addEventListener(`hashchange`,e),()=>removeEventListener(`hashchange`,e)});let a=lt(()=>J(i).match(/^#\/changes\/(\d+)$/)?.[1]);async function o(){await bi().catch(()=>{}),location.assign(`/login`)}var s=Ba(),c=I(s),l=R(F(c),2),u=F(l);let d;var f=R(u,2);let p;var m=R(f,2);let h;var g=R(m,2);let _;var v=R(g,2);let y;O(l);var b=R(l,2),x=e=>{var t=La(),n=R(F(t)),i=L(n,!0),a=R(n,2),o=L(a),s=L(R(a,2),!0);O(t),z(()=>{Z(i,J(r).database),Z(o,`${J(r).host??``}:${J(r).port??``}`),Z(s,J(r).user)}),X(e,t)};Q(b,e=>{J(r)&&e(x)});var S=R(b,2),C=F(S),ee=e=>{var t=Ra(),r=I(t),i=R(r);z(()=>Z(r,`${J(n)??``} `)),cr(`click`,i,o),X(e,t)};Q(C,e=>{J(n)&&e(ee)}),O(S),O(c);var te=R(c,2),ne=F(te),re=e=>{X(e,za())},ie=e=>{var t=vr();kr(I(t),()=>J(a),e=>{Ji(e,{get id(){return J(a)}})}),X(e,t)},ae=e=>{ca(e,{})},oe=e=>{Ia(e,{})},se=e=>{ea(e,{})},ce=e=>{ka(e,{})},le=e=>{ga(e,{})};Q(ne,e=>{J(n)?J(a)?e(ie,1):J(i)===`#/log`?e(ae,2):J(i)===`#/shadow`?e(oe,3):J(i)===`#/notifications`?e(se,4):J(i)===`#/setup`?e(ce,5):e(le,-1):e(re)}),O(te),z(()=>{d=Vr(u,1,``,null,d,{active:J(i)===``||J(i)===`#/`}),p=Vr(f,1,``,null,p,{active:J(i)===`#/log`}),h=Vr(m,1,``,null,h,{active:J(i)===`#/shadow`}),_=Vr(g,1,``,null,_,{active:J(i)===`#/notifications`}),y=Vr(v,1,``,null,y,{active:J(i)===`#/setup`})}),X(e,s),He()}lr([`click`]),Cr(Va,{target:document.getElementById(`app`)}); \ No newline at end of file diff --git a/crates/rowbit-web/src/api.rs b/crates/rowbit-web/src/api.rs index 7f12be6..0eba154 100644 --- a/crates/rowbit-web/src/api.rs +++ b/crates/rowbit-web/src/api.rs @@ -466,6 +466,28 @@ pub(crate) async fn verify(State(app): State, headers: HeaderMap) -> Respon } } +/// What this Rowbit guards and who is connected: the Setup view. +pub(crate) async fn setup(State(app): State, headers: HeaderMap) -> Response { + if let Err(r) = signed_in(&app, &headers) { + return r.into_response(); + } + let agents = match app.engine.agents_overview() { + Ok(a) => a, + Err(e) => return error(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()), + }; + let held = match app.engine.held() { + Ok(h) => h.len(), + Err(e) => return error(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()), + }; + let mut out = (*app.setup).clone(); + if !out.is_object() { + out = json!({}); + } + out["agents"] = json!(agents); + out["held"] = json!(held); + Json(out).into_response() +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rowbit-web/src/lib.rs b/crates/rowbit-web/src/lib.rs index e3d8ee5..9a0f36a 100644 --- a/crates/rowbit-web/src/lib.rs +++ b/crates/rowbit-web/src/lib.rs @@ -69,6 +69,9 @@ pub struct Web { pub secure: bool, /// Serve agents over MCP at `/mcp`, with this default database. pub mcp: Option, + /// What the Setup view shows besides the agents: the database without + /// its password, Rowbit's directory, sign-in. Built by `rowbit serve`. + pub setup: serde_json::Value, } #[derive(Clone)] @@ -78,6 +81,7 @@ struct App { sign_in: Arc, secure: bool, sessions: Arc>>, + setup: Arc, /// Wrong passwords in a row, across all clients. Held for the whole of /// a sign-in, so passwords are checked one at a time and each wrong one /// waits longer: the wait caps the guessing rate, and only one Argon2 @@ -109,6 +113,7 @@ pub fn router(engine: Arc, web: Web) -> Router { sign_in: Arc::new(web.sign_in), secure: web.secure, sessions: Arc::new(Mutex::new(HashMap::new())), + setup: Arc::new(web.setup), failures: Arc::new(tokio::sync::Mutex::new(0)), }; Router::new() @@ -127,6 +132,7 @@ pub fn router(engine: Arc, web: Web) -> Router { .route("/api/changes/{id}/reject", post(api::reject)) .route("/api/changes/{id}/undo", post(api::undo)) .route("/api/verify", get(api::verify)) + .route("/api/setup", get(api::setup)) .route("/api/deliveries", get(api::deliveries)) .merge(match mcp { // Every request signs in with its agent's token first. diff --git a/crates/rowbit-web/tests/mcp_http.rs b/crates/rowbit-web/tests/mcp_http.rs index d23bf0e..8f1deeb 100644 --- a/crates/rowbit-web/tests/mcp_http.rs +++ b/crates/rowbit-web/tests/mcp_http.rs @@ -45,6 +45,7 @@ async fn server(url: &str) -> Server { let router = rowbit_web::router( engine, rowbit_web::Web { + setup: serde_json::Value::Null, sign_in: rowbit_web::SignIn::Password { hash: rowbit_web::hash_password(&rowbit_web::new_password()), }, diff --git a/crates/rowbit-web/tests/oidc.rs b/crates/rowbit-web/tests/oidc.rs index c4917c4..49e990a 100644 --- a/crates/rowbit-web/tests/oidc.rs +++ b/crates/rowbit-web/tests/oidc.rs @@ -222,6 +222,7 @@ async fn rowbit(p: &Provider) -> axum::Router { rowbit_web::router( engine, rowbit_web::Web { + setup: serde_json::Value::Null, sign_in: rowbit_web::SignIn::Oidc(Box::new(login)), hosts: vec![HOST.into()], secure: false, diff --git a/crates/rowbit-web/tests/page.rs b/crates/rowbit-web/tests/page.rs index 511e2ac..a024821 100644 --- a/crates/rowbit-web/tests/page.rs +++ b/crates/rowbit-web/tests/page.rs @@ -49,6 +49,7 @@ impl Page { router: rowbit_web::router( engine.clone(), rowbit_web::Web { + setup: serde_json::Value::Null, sign_in: rowbit_web::SignIn::Password { hash }, hosts: vec![HOST.to_owned()], secure: false, @@ -349,6 +350,8 @@ async fn other_hosts_are_refused_and_the_ui_needs_a_session() { assert_eq!(status, StatusCode::SEE_OTHER, "{html}"); let (status, _) = page.api("/api/changes").await; assert_eq!(status, StatusCode::UNAUTHORIZED); + let (status, _) = page.api("/api/setup").await; + assert_eq!(status, StatusCode::UNAUTHORIZED); // Found by a browser test: with `Referrer-Policy: no-referrer`, browsers // send `Origin: null` on the page's own forms, so the origin check @@ -383,6 +386,14 @@ async fn other_hosts_are_refused_and_the_ui_needs_a_session() { ); let (_, me) = page.api("/api/session").await; assert_eq!(me["reviewer"], "philip"); + // The Setup view: every agent in rowbit.yml, and nothing held yet. + let (status, setup) = page.api("/api/setup").await; + assert_eq!(status, StatusCode::OK); + assert_eq!(setup["held"], 0); + assert!( + setup["agents"].as_array().is_some_and(|a| !a.is_empty()), + "{setup}" + ); let (status, js) = page.get_path(HOST, "/assets/app.js").await; assert_eq!(status, StatusCode::OK); assert!(!js.is_empty()); diff --git a/docs/connect.md b/docs/connect.md index e8f4bbd..d1e1a66 100644 --- a/docs/connect.md +++ b/docs/connect.md @@ -16,7 +16,7 @@ cd ~/projects/my-app rowbit connect claude-code ``` -Rowbit finds its setup on its own: the folder's `rowbit.yml` if it has one, else `~/.rowbit/default`, else your only setup in `~/.rowbit` or the demo, and says which it used. With several and no `default`, it lists them and asks for `--dir`. For Claude Code the entry applies to this project only, so other projects don't see Rowbit; `--scope user` adds it everywhere. Each project you connect gets a token of its own, so connecting a second project doesn't sign out the first, and `rowbit agents` lists them all. +Rowbit finds its setup on its own: the folder's `rowbit.yml` if it has one, else `~/.rowbit/default`, else your only setup in `~/.rowbit` or the demo, and says which it used. With several and no `default`, it lists them and asks for `--dir`. For Claude Code the entry applies to this project only, so other projects don't see Rowbit; `--scope user` adds it everywhere. Each project you connect gets a token of its own, so connecting a second project doesn't sign out the first. `rowbit status` lists every setup, the database each guards and where each agent is connected; the review page's Setup view shows the same for its own. Rowbit doesn't write `.mcp.json` (Claude Code's project scope), since that file is meant to be committed and would carry the token. diff --git a/docs/quickstart.md b/docs/quickstart.md index 422c4c0..59bbf49 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -57,7 +57,9 @@ Then ask for a change. Whatever it is, Rowbit previews it on a copy and holds it ## 4. Review it -Open the review page and sign in with the password setup printed and your name, which the audit log records. It shows the held change with each row before and after. Approve it, and Rowbit writes exactly those rows, or nothing if any changed since the preview. Undo takes one change back. +Open the review page and sign in with the password setup printed and your name, which the audit log records. It shows the held change with each row before and after. Approve it, and Rowbit writes exactly those rows, or nothing if any changed since the preview. Undo takes one change back. Its header says which database it guards, and its Setup view shows the database, the agents and where each is connected; `rowbit status` shows the same for every setup on this machine. + +To use Rowbit in another project, `cd` into it and run `rowbit connect claude-code` (or another client); see [Connect your agent](connect.md#add-rowbit-to-a-project-you-already-have). The same from a terminal: diff --git a/docs/spec/server.md b/docs/spec/server.md index 0a41585..c751dc7 100644 --- a/docs/spec/server.md +++ b/docs/spec/server.md @@ -65,6 +65,8 @@ Reviewers sign in to the web UI through an OpenID Connect provider: Google Works - `reviewers.allow` decides who may sign in: an exact `emails` entry, an email in one of the `domains`, or membership of one of the `groups` (the token's `groups` claim). Anyone else is refused, and an empty `allow` refuses everyone. - The audit log records the reviewer as `human:`. +Everyone who can sign in also sees the Setup view: the database's host, port, user and name, Rowbit's folder, this identity provider, the notification targets' names and each agent connection's label (see [What Rowbit is connected to](setup.md#what-rowbit-is-connected-to)). No secrets, but more than which changes are held. + Sessions live in memory, so restarting `rowbit serve` signs everyone out. Signing in gives the same session as v0.1: an `HttpOnly`, `SameSite=Strict` cookie (and `Secure` behind HTTPS), valid for 12 hours or until the process stops, and a per-session token every action must send. The short-lived cookie that brings the browser back to its login is `SameSite=Lax`, since the provider's redirect back is a cross-site navigation; it holds only a random id, while `state`, `nonce` and the PKCE verifier stay in Rowbit's memory, and each login can be finished once, within 10 minutes. After sign-in, the callback answers with a page that moves on to the queue itself, because browsers don't send a `SameSite=Strict` cookie on a redirect chain that started at another site. **Without `reviewers.oidc`,** `rowbit serve` keeps v0.1's shared password and typed name, but only on a loopback address. It refuses to listen anywhere else, so the password never crosses a network. This is for trying Rowbit on one machine. diff --git a/docs/spec/setup.md b/docs/spec/setup.md index bb290c2..196beaf 100644 --- a/docs/spec/setup.md +++ b/docs/spec/setup.md @@ -190,6 +190,25 @@ The home page and the README also offer install links for VS Code (`https://insi So that a held write ends with the person knowing where to look, `propose_write` and `change_status` return `review_url` for a held change: `/changes/`, or `http:///changes/` without a `public_url`, the same link notifications use. `rowbit serve` records that address in the state file when it starts, so `rowbit mcp` over stdio, which shares the file, links to the same place; before `rowbit serve` has ever run, the link uses `http://127.0.0.1:8080`. The server's instructions tell the agent to give the person that link, as a link whose text is the URL itself (``), so clients that render Markdown make it clickable while the person still sees where it goes (a link labelled "Review change 4" could hide a look-alike page asking for the review password), and not to retry the write in another form. The link reveals nothing: the page needs sign-in, and the agent could reach its address already. Opened signed out, it goes through sign-in (carrying only the change's number) and then to that change. See [Agent tools](change-lifecycle.md#agent-tools-mcp). +## What Rowbit is connected to + +`rowbit status` lists every setup on this machine: those in `~/.rowbit` and the demo, or with `--dir` (or in a folder of Rowbit's) that one. For each it prints its folder; the database it guards, as database, host, port, user and TLS, never the password; the review page's address and whether a Rowbit review page answers there (two setups on one address can't be told apart), with the number of held changes; and each agent in `rowbit.yml` with its rules in brief ("holds every write", "3 rules, else holds", shadow mode, scoped) and where it is connected. It reads files, opening each state file read-only, and never connects to the database, so it works when the database is down; a state file it can't read is reported as such, never as "not connected". Each connection is listed with its id, and the command to sign one out. + +``` +shop ~/.rowbit/shop + database: shop on db.internal:3306 as rowbit, TLS, certificate and host name checked + review page: http://127.0.0.1:8080/, running, 2 held + agent claude-code: holds every write + Claude Code in ~/projects/my-app (last used 2026-11-07T14:02:11Z) + Cursor (never used) +demo ~/rowbit-demo + ... +``` + +Where an agent is connected comes from its tokens over HTTP: each entry `rowbit connect` added, by its label, and the token from `rowbit agents token`. An entry for `rowbit mcp` over stdio holds no token, so it isn't listed. A label says where an entry was added; removing the entry by hand in the client leaves the token, and so the line, until `rowbit agents revoke`. + +The review page shows the same for its own setup: a line in the header ("Guarding shop on db.internal:3306 as rowbit", linking to the Setup view), and a Setup view with the database, Rowbit's folder, review page and MCP addresses, sign-in, notification targets, the number held, the version, and each agent with its rules and connections, each with when it was made and last used. The page reads it from `/api/setup`, behind the same sign-in as everything else. So everyone who can review sees it: the database's host, port, user and name, Rowbit's folder, the identity provider, the notification targets' names, and each connection's label, which names a developer's project folder. None of it is a secret, and a reviewer approving a change should know which database it writes to; with OIDC sign-in, keep that in mind when choosing who may review. One review page shows one setup; a page across several databases comes with named connections. + ## Links in the terminal A plain URL in a terminal is only clickable if the terminal spots it, and some open it only on ⌘-click or Ctrl-click. So where Rowbit prints an address for a person (the review page in `setup`, `demo` and `serve`, the docs link in `setup`), it marks it as a link with OSC 8, in terminals known to show those: Ghostty, iTerm2, WezTerm, kitty, VS Code's terminal, Windows Terminal, Hyper, Rio, Warp and VTE-based ones (GNOME Terminal and others). It prints the address as it is when the output isn't a terminal, in Terminal.app, which doesn't support them, and inside tmux or screen, which drop them unless set up to pass them on. `ROWBIT_HYPERLINKS=1` or `0` overrides the choice. The link's text is the address itself, so copying still works. diff --git a/web/src/App.svelte b/web/src/App.svelte index 0dd7024..a52137f 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -5,13 +5,18 @@ import Deliveries from './Deliveries.svelte'; import Log from './Log.svelte'; import Queue from './Queue.svelte'; + import Setup from './Setup.svelte'; import Shadow from './Shadow.svelte'; let reviewer = $state(''); + let guarding = $state(null); let route = $state(location.hash); onMount(() => { - api.me().then((s) => (reviewer = s.reviewer)); + api.me().then((s) => { + reviewer = s.reviewer; + api.setup().then((s) => (guarding = s.database)).catch(() => {}); + }); const onHash = () => (route = location.hash); addEventListener('hashchange', onHash); return () => removeEventListener('hashchange', onHash); @@ -32,7 +37,13 @@ Log Shadow Notifications + Setup + {#if guarding} + + Guarding {guarding.database} on {guarding.host}:{guarding.port} as {guarding.user} + + {/if} {#if reviewer}{reviewer} {/if} @@ -49,6 +60,8 @@ {:else if route === '#/notifications'} + {:else if route === '#/setup'} + {:else} {/if} diff --git a/web/src/Setup.svelte b/web/src/Setup.svelte new file mode 100644 index 0000000..58c8a99 --- /dev/null +++ b/web/src/Setup.svelte @@ -0,0 +1,95 @@ + + +

Setup

+

+ What this Rowbit guards, and where its agents are connected. Passwords are never shown. + rowbit status shows the same for every setup on this machine. +

+{#if error}

{error}

{/if} +{#if setup} +
+

Database

+ {#if setup.database} +
+
Database
{setup.database.database}
+
Server
{setup.database.host}:{setup.database.port} (MariaDB or MySQL)
+
Rowbit connects as
{setup.database.user}
+
Connection
{setup.database.tls}
+
+ {:else} +

Unknown: the database URL isn't available to the review page.

+ {/if} +
+ +
+

Rowbit

+
+ {#if setup.dir}
Files
{setup.dir}
{/if} +
Review page
{setup.review_page}
+
Sign-in
{setup.sign_in}
+
Agents over HTTP
{setup.mcp ?? 'off (agents start rowbit mcp themselves)'}
+ {#if setup.notify?.length}
Notifications
{setup.notify.join(', ')}
{/if} +
Held now
{setup.held}
+
Version
{setup.version}
+
+
+ +
+

Agents

+ {#each setup.agents as a (a.id)} +

{a.id}

+ {#if a.description}

{a.description}

{/if} +

{rules(a)}

+ {#if a.connections.length} +
+ + + + {#each a.connections as c (c.id)} + + + + + + + {/each} + +
ConnectedIdSinceLast used
{c.label}{c.id}{ago(c.created_ms)}{c.used_ms ? ago(c.used_ms) : 'never'}
+
+

Sign one out: rowbit agents revoke {a.id} --connection <id>

+ {:else} +

Not connected over HTTP. Connect a client from your project: rowbit connect claude-code

+ {/if} + {/each} +
+{/if} diff --git a/web/src/api.js b/web/src/api.js index 1d266cf..3e7d70d 100644 --- a/web/src/api.js +++ b/web/src/api.js @@ -47,4 +47,5 @@ export const reject = (id, reason) => call('POST', `/api/changes/${id}/reject`, export const undo = (id) => call('POST', `/api/changes/${id}/undo`, {}); export const verify = () => call('GET', '/api/verify'); export const deliveries = () => call('GET', '/api/deliveries'); +export const setup = () => call('GET', '/api/setup'); export const logout = () => call('POST', '/api/logout', {}); diff --git a/web/src/app.css b/web/src/app.css index b5f7501..e7f3cb9 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -74,3 +74,11 @@ button.link { border: 0; background: none; color: var(--accent); padding: 0; } .pager { display: flex; gap: 12px; align-items: center; } :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .shadow { color: var(--held); } + +header .guarding { color: var(--muted); text-decoration: none; font-size: 0.9rem; } +header .guarding:hover { color: var(--ink); } +header .guarding code { color: var(--ink); } +.facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 0; } +.facts dt { color: var(--muted); } +.facts dd { margin: 0; overflow-wrap: anywhere; } +h3 { font-size: 1rem; margin: 16px 0 4px; }