Host: the store's commands (install links, dropped files, the signed Store, the install screen) are served for every app that sets AppConfig::with_store; commands::STORE, testkit::assert_shell_only_group and assert_store_guards

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CRTkafa 2026-10-01 03:40:37 +07:00
parent 06e830b132
commit 3450eac09a
5 changed files with 230 additions and 6 deletions

View file

@ -45,9 +45,25 @@ pub const TAB: &[&str] = &["tab_shortcut", "tab_link_drag"];
/// 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",
];
/// 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)
SHELL.contains(&command) || TAB.contains(&command) || SITE.contains(&command) || STORE.contains(&command)
}
/// The capability permission tauri-build generates for `command` (`tabs_sync` → `allow-tabs-sync`).
@ -62,8 +78,8 @@ pub fn permission(command: &str) -> String {
/// 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());
for command in app.iter().chain(SHELL).chain(TAB).chain(SITE) {
let mut all: Vec<&'static str> = Vec::with_capacity(app.len() + SHELL.len() + TAB.len() + SITE.len() + STORE.len());
for command in app.iter().chain(SHELL).chain(TAB).chain(SITE).chain(STORE) {
if !all.contains(command) {
all.push(command);
}
@ -80,7 +96,7 @@ mod tests {
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) {
for command in SHELL.iter().chain(TAB).chain(SITE).chain(STORE) {
assert!(all.contains(command), "{command}");
assert!(is_host(command));
}
@ -90,7 +106,7 @@ mod tests {
#[test]
fn shell_and_tab_commands_do_not_overlap() {
assert!(!SHELL.iter().any(|command| TAB.contains(command) || SITE.contains(command)));
assert!(!SHELL.iter().any(|command| TAB.contains(command) || SITE.contains(command) || STORE.contains(command)));
assert!(!TAB.iter().any(|command| SITE.contains(command)));
}
}