waybetter/crates/waybetter-host/src/commands.rs
CRT 825742b964 Repair: the Google Fonts host commands as 7f9e172 meant them (a staging race split them from 43fc8a1)
Two agents staged the same host files at once: 7f9e172 went in with the diagnostics' hunks of app.rs, commands.rs and lib.rs instead of its own, and 43fc8a1 then dropped fonts_commands.rs. This puts back exactly the Google Fonts wiring from the working tree (AppConfig::with_fonts, SiteHooks::fonts_changed, commands::GFONTS, the fonts handler, fonts_commands.rs); the diagnostics stay as committed. theme.rs, still in progress, is not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 04:12:43 +07:00

137 lines
5.1 KiB
Rust

//! The Tauri commands [`crate::app::run_app`] registers for every app, and who may call them.
//!
//! An app's `build.rs` lists its own commands plus these in the app-command manifest
//! ([`manifest`]), and its capability files grant [`SHELL`] to the local `shell` webview only,
//! [`TAB`] to tab webviews only and [`SITE`] to tab webviews on the site's origin only;
//! [`crate::testkit`] checks them. Every command re-checks its caller natively
//! (`host::shell_only` / `host::tab_only` / `host::site_tab_only`) before anything else.
/// Shell-only: the local `shell` webview (debug builds also accept the dev server).
pub const SHELL: &[&str] = &[
"tabs_sync",
"tab_navigate",
"tab_action",
"tab_zoom",
"tab_find",
"safe_mode_get",
"safe_mode_set",
"diag_get",
"diag_log",
"open_external_url",
"shell_focus",
"shell_ready",
"tab_still_ready",
"shell_raise",
"window_system_menu",
"profiles_get",
"profiles_set",
"i18n_get",
"i18n_set",
"plugins_list",
"plugin_set_enabled",
"plugins_open_folder",
"custom_css_get",
"custom_css_set",
"features_get",
"features_set",
"mode_get",
"mode_set",
"settings_get",
"settings_set",
];
/// Tab-only: any tab webview, speaking only about itself.
pub const TAB: &[&str] = &["tab_shortcut", "tab_link_drag"];
/// Site-tab-only: a tab webview that is on the site's origin right now (the page runtime asks
/// the shell to open the app's panel). Grant these in a capability limited to the site's URLs.
pub const SITE: &[&str] = &["open_panel"];
/// Shell-only, optional: the store's commands (install links, dropped files, the signed Store and
/// the install screen), served when the app sets `AppConfig::store`. An app that uses the store
/// grants these to the shell (`testkit::Capabilities::assert_shell_only_group`).
pub const STORE: &[&str] = &[
"install_pending",
"install_stage_link",
"install_stage_file",
"install_cancel",
"install_commit",
"plugin_remove",
"install_records",
"install_forget",
"store_catalog",
"store_stage",
"strings_list",
"strings_read",
"strings_set",
"strings_remove",
"strings_apply",
];
/// Shell-only, optional: the media panel's commands (gallery folders, previews, the clipboard
/// history), served when the app sets `AppConfig::media`. An app that uses them grants these to the
/// shell (`testkit::Capabilities::assert_shell_only_group`).
pub const MEDIA: &[&str] = &[
"media_get",
"media_set",
"gallery_add_folder",
"gallery_list",
"gallery_thumb",
"clip_list",
"clip_thumb",
"clip_remove",
];
/// Shell-only, optional: Google Fonts (what is installed, install, remove, the faces of a family and
/// a preview), served when the app sets `AppConfig::fonts`; needs the `net` feature.
pub const GFONTS: &[&str] = &["gfonts_installed", "gfonts_install", "gfonts_remove", "gfonts_faces", "gfonts_preview"];
/// Whether `command` is one of the host's (dispatched to the host, never to the app's handler).
pub fn is_host(command: &str) -> bool {
SHELL.contains(&command) || TAB.contains(&command) || SITE.contains(&command) || STORE.contains(&command) || MEDIA.contains(&command) || GFONTS.contains(&command)
}
/// The capability permission tauri-build generates for `command` (`tabs_sync` → `allow-tabs-sync`).
pub fn permission(command: &str) -> String {
format!("allow-{}", command.replace('_', "-"))
}
/// The app-command manifest for `build.rs`: the app's own commands followed by the host's (each
/// once). Leaked on purpose: tauri-build wants `&'static` and a build script runs once.
///
/// ```ignore
/// tauri_build::AppManifest::new().commands(waybetter_host::commands::manifest(&["draft_list"]))
/// ```
pub fn manifest(app: &[&'static str]) -> &'static [&'static str] {
let mut all: Vec<&'static str> = Vec::with_capacity(app.len() + SHELL.len() + TAB.len() + SITE.len() + STORE.len() + MEDIA.len() + GFONTS.len());
for command in app.iter().chain(SHELL).chain(TAB).chain(SITE).chain(STORE).chain(MEDIA).chain(GFONTS) {
if !all.contains(command) {
all.push(command);
}
}
Box::leak(all.into_boxed_slice())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn manifest_adds_the_host_commands_once() {
let all = manifest(&["draft_list", "tabs_sync"]);
assert_eq!(all[0], "draft_list");
assert_eq!(all.iter().filter(|c| **c == "tabs_sync").count(), 1);
for command in SHELL.iter().chain(TAB).chain(SITE).chain(STORE).chain(MEDIA).chain(GFONTS) {
assert!(all.contains(command), "{command}");
assert!(is_host(command));
}
assert!(!is_host("draft_list"));
assert_eq!(permission("tab_link_drag"), "allow-tab-link-drag");
}
#[test]
fn shell_and_tab_commands_do_not_overlap() {
assert!(!SHELL.iter().any(|command| TAB.contains(command) || SITE.contains(command) || STORE.contains(command) || MEDIA.contains(command) || GFONTS.contains(command)));
assert!(!TAB.iter().any(|command| SITE.contains(command)));
}
}