diff --git a/.gitignore b/.gitignore index ff71fd1..2d417f6 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,10 @@ cache/ # Build artifacts *.log + +#Playwright +playwright-report/ +test-results/ + +# AI Tools +beledarian_info.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ad78b85 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,40 @@ +# Praetorian AI Agent Instructions + +These instructions help AI coding agents understand the workspace structure, build commands, and the current model/face-detection architecture. + +## Key points + +- This is a Tauri desktop app with a React frontend in `src/` and a Rust backend in `src-tauri/`. +- Frontend UI calls backend commands through `src/services/catalog.ts` and state is managed in `src/hooks/useCatalog.ts`. +- The Rust backend exposes catalog, image, face, and Python-upscaling commands in `src-tauri/src/lib.rs`. +- The catalog engine is implemented in `src-tauri/src/catalog/manager.rs` with SQLite and image metadata handling. +- Face detection is implemented under `src-tauri/src/face/` using ONNX Runtime and a RetinaFace model. +- The Python bridge is implemented under `src-tauri/src/python/` and is used for external upscaling workflows. + +## Model / AI conventions + +- Model code is primarily in Rust; do not move face-detection logic into the React frontend. +- The face detection flow is feature-gated with `#[cfg(feature = "face-detection")]` and initializes `retinaface.onnx` in `src-tauri/src/lib.rs`. +- Use the existing Tauri command patterns when adding or changing model features: backend command -> `src/services/catalog.ts` invoke -> frontend hook/component. +- Prefer GPU execution providers for ONNX Runtime when available, but maintain fallback behavior. + +## Build and run commands + +- `npm install` to install the frontend dependencies. +- `npm run dev` to start Vite in development. +- `npm run build` to build the frontend (`tsc && vite build`). +- `npm run tauri` to run the Tauri app. +- `npm run tauri build` to build the desktop application in `src-tauri/target/release`. + +## Documentation links + +- Project overview: [README.md](README.md) +- AI / model requirements: [REQUIREMENTS.md](REQUIREMENTS.md) +- Initial Prompt: [PROMPT.md](PROMPT.md) + +## Guidance for AI agents + +- Keep UI and backend responsibilities distinct. +- Preserve the existing Tauri command and IPC structure. +- When updating face or model-related behavior, check both Rust backend and TypeScript frontend call sites. +- Avoid duplicating README or requirements content; link to those docs instead. diff --git a/PROMPT.md b/PROMPT.md index 6dda86f..7c7480a 100644 --- a/PROMPT.md +++ b/PROMPT.md @@ -18,8 +18,10 @@ Prompt: Implement the libvips background worker to generate thumbnails and smart ## Iteration C Prompt: "Integrate ONNX Runtime for face detection using GPU acceleration." + --- + # Full Project Requirements ## Role @@ -78,3 +80,147 @@ Please provide: 4. **Python Bridge Skeleton:** A basic example of how the Rust backend would call a Python script to upscale an image and return the result path. Start by defining the `Cargo.toml` dependencies required for GPU-accelerated AI and libvips, then outline the core database schema. + + +--- + +# Design Mockups + +``` +Create a high-fidelity desktop application UI mockup for a professional photo management application named "Praetorian." + +Design language: +- Modern, premium creative software +- Dark mode +- Inspired by Lightroom Cloud, Capture One, Arc Browser, and Linear +- Matte charcoal interface (#181818 to #222222) +- Soft elevation with subtle shadows +- 8px spacing system +- Rounded corners (8px) +- Thin separators instead of heavy borders +- Clean typography similar to Inter or SF Pro +- Pixel-perfect alignment +- Production-quality Figma design +- Extremely polished UX +- No futuristic or glass-heavy effects + +Window: +- Native desktop application +- 16:10 aspect ratio +- Large 1440p workspace +- macOS-style window chrome +- Professional creative application + +Layout: +Left Sidebar +- Library +- Collections +- Favorites +- Recent Imports +- External Drives +- Folder tree +- Smart Albums +- Collapsible sections +- Clean monochrome icons + +Center Workspace +- Primary content area +- Dense but elegant layout +- Excellent spacing +- Strong visual hierarchy + +Right Sidebar +- Context-sensitive inspector +- Metadata +- EXIF +- Camera +- Lens +- Histogram +- Keywords +- Rating +- Color labels + +The interface should feel like software used by professional photographers managing hundreds of thousands of RAW images. + +Generate the "Import Photos" dialog. + +The dialog should appear centered over the library. + +Dialog layout: + +Left Column +- Connected devices +- SD cards +- External SSDs +- NAS locations +- Local folders +- Recently used sources + +Center +- Thumbnail preview grid +- 30–50 photo thumbnails +- Portrait photography +- Every thumbnail is unique +- Mix of RAW and JPEG indicators +- Multi-select checkboxes +- File names +- Capture dates +- File sizes + +Top Toolbar +- Breadcrumb navigation +- Search +- Filter +- Sort +- Select All +- Number of selected photos + +Right Panel +Import Options + +Destination +- Folder picker +- Create dated folder +- Custom folder name + +File Handling +- Copy +- Move +- Leave in place + +Renaming +- Rename using template +- Sequence numbering + +Metadata +- Apply copyright +- Apply keywords +- Apply preset +- Apply star rating + +AI Options +- Generate Smart Keywords +- Detect Faces +- Detect Duplicate Photos +- Estimate Image Quality +- Build Search Index + +Bottom Bar +- Selected item count +- Total storage required +- Cancel button +- Large blue "Import 248 Photos" button + +Visual Details +- Beautiful thumbnail photography +- Realistic icons +- Crisp typography +- Realistic spacing +- Professional UI polish +- Subtle hover states +- Soft blue accent color +- Clean monochrome iconography +- Consistent design system + +The mockup should be indistinguishable from a real shipping desktop application screenshot. No placeholder boxes, no lorem ipsum, no wireframe styling. +``` \ No newline at end of file diff --git a/design/mockups/00017-419623986.png b/design/mockups/00017-419623986.png deleted file mode 100644 index a00f605..0000000 Binary files a/design/mockups/00017-419623986.png and /dev/null differ diff --git a/design/mockups/00022-1383062596.png b/design/mockups/00022-1383062596.png deleted file mode 100644 index 0d099e7..0000000 Binary files a/design/mockups/00022-1383062596.png and /dev/null differ diff --git a/design/mockups/Gemini_Generated_Image_k6brd6k6brd6k6br.png b/design/mockups/Gemini_Generated_Image_k6brd6k6brd6k6br.png deleted file mode 100644 index 7247824..0000000 Binary files a/design/mockups/Gemini_Generated_Image_k6brd6k6brd6k6br.png and /dev/null differ diff --git a/design/mockups/import-menu.png b/design/mockups/import-menu.png new file mode 100644 index 0000000..d24f794 Binary files /dev/null and b/design/mockups/import-menu.png differ diff --git a/design/mockups/main-gallery-grid-option-2.png b/design/mockups/main-gallery-grid-option-2.png new file mode 100644 index 0000000..3a524c7 Binary files /dev/null and b/design/mockups/main-gallery-grid-option-2.png differ diff --git a/design/mockups/main-gallery-grid.png b/design/mockups/main-gallery-grid.png new file mode 100644 index 0000000..dcecb39 Binary files /dev/null and b/design/mockups/main-gallery-grid.png differ diff --git a/design/mockups/people-faces-dialog.png b/design/mockups/people-faces-dialog.png new file mode 100644 index 0000000..d22a1be Binary files /dev/null and b/design/mockups/people-faces-dialog.png differ diff --git a/src-tauri/.cargo/config.toml b/src-tauri/.cargo/config.toml index eab5274..f7f3322 100644 --- a/src-tauri/.cargo/config.toml +++ b/src-tauri/.cargo/config.toml @@ -3,6 +3,8 @@ rustflags = ["-C", "target-cpu=native"] [env] SQLX_OFFLINE = "true" +# vips-sys does not pass VIPS_ROOT/include to bindgen's clang, so we set it here. +BINDGEN_EXTRA_CLANG_ARGS = { value = "-I'C:/Program Files/vips/vips-dev-8.18/include' -I'C:/Program Files/vips/vips-dev-8.18/include/glib-2.0' -I'C:/Program Files/vips/vips-dev-8.18/lib/glib-2.0/include'", force = true } [target.x86_64-unknown-linux-gnu] linker = "clang" diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e698d60..012e4c8 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3543,6 +3543,7 @@ dependencies = [ "tracing-subscriber", "uuid", "vips", + "vips-sys", "walkdir", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5f8c964..feecd5a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ tauri-build = { version = "2", features = [] } [dependencies] # --- Tauri v2 --- -tauri = { version = "2" } +tauri = { version = "2", features = [] } tauri-plugin-log = "2" tauri-plugin-fs = "2" tauri-plugin-dialog = "2" @@ -27,20 +27,24 @@ serde_json = "1" tokio = { version = "1", features = ["full"] } # --- Database: sqlx with SQLite --- +# "offline" feature allows compile-time query checking without a live DB. sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "chrono", "macros"] } # --- Image processing --- -vips = "0.1.0-alpha.5" +# vips is optional; falls back to the `image` crate when libvips is unavailable. +vips = { version = "0.1.0-alpha.5", optional = true } +vips-sys = { version = "0.1.3-beta.2", optional = true } image = "0.25" # --- EXIF / metadata parsing --- exif = { package = "kamadak-exif", version = "0.6" } # --- ONNX Runtime (GPU-accelerated face detection) --- +# Optional: enable with --features face-detection # CUDA support enabled via the "cuda" feature. # "load-dynamic" loads CUDA libraries at runtime rather than link time. -ort = { version = "2.0.0-rc.12", features = ["cuda", "load-dynamic"] } -ort-sys = "2.0.0-rc.12" +ort = { version = "2.0.0-rc.12", features = ["cuda", "load-dynamic"], optional = true } +ort-sys = { version = "2.0.0-rc.12", optional = true } # --- UUID for hashed cache keys --- uuid = { version = "1", features = ["v4"] } @@ -68,6 +72,8 @@ duct = "0.13" [features] default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] +vips = ["dep:vips", "dep:vips-sys"] +face-detection = ["dep:ort", "dep:ort-sys"] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-updater = "2" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..3d652fe --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://raw.githubusercontent.com/nicegram/tauri/v2.0.0/tooling/cli/src/helpers/json-schemas/capabilities.json", + "identifier": "default", + "description": "Default capabilities for Praetorian", + "windows": ["main"], + "permissions": [ + "core:default", + "dialog:allow-open", + "dialog:allow-save", + "fs:default", + "shell:default" + ] +} diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json index fa66db5..77d0669 100644 --- a/src-tauri/gen/schemas/acl-manifests.json +++ b/src-tauri/gen/schemas/acl-manifests.json @@ -1,7227 +1 @@ -{ - "core": { - "default_permission": { - "identifier": "default", - "description": "Default core plugins set.", - "permissions": [ - "core:path:default", - "core:event:default", - "core:window:default", - "core:webview:default", - "core:app:default", - "core:image:default", - "core:resources:default", - "core:menu:default", - "core:tray:default" - ] - }, - "permissions": {}, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:app": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin.", - "permissions": [ - "allow-version", - "allow-name", - "allow-tauri-version", - "allow-identifier", - "allow-bundle-type", - "allow-register-listener", - "allow-remove-listener", - "allow-supports-multiple-windows" - ] - }, - "permissions": { - "allow-app-hide": { - "identifier": "allow-app-hide", - "description": "Enables the app_hide command without any pre-configured scope.", - "commands": { - "allow": [ - "app_hide" - ], - "deny": [] - } - }, - "allow-app-show": { - "identifier": "allow-app-show", - "description": "Enables the app_show command without any pre-configured scope.", - "commands": { - "allow": [ - "app_show" - ], - "deny": [] - } - }, - "allow-bundle-type": { - "identifier": "allow-bundle-type", - "description": "Enables the bundle_type command without any pre-configured scope.", - "commands": { - "allow": [ - "bundle_type" - ], - "deny": [] - } - }, - "allow-default-window-icon": { - "identifier": "allow-default-window-icon", - "description": "Enables the default_window_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "default_window_icon" - ], - "deny": [] - } - }, - "allow-fetch-data-store-identifiers": { - "identifier": "allow-fetch-data-store-identifiers", - "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", - "commands": { - "allow": [ - "fetch_data_store_identifiers" - ], - "deny": [] - } - }, - "allow-identifier": { - "identifier": "allow-identifier", - "description": "Enables the identifier command without any pre-configured scope.", - "commands": { - "allow": [ - "identifier" - ], - "deny": [] - } - }, - "allow-name": { - "identifier": "allow-name", - "description": "Enables the name command without any pre-configured scope.", - "commands": { - "allow": [ - "name" - ], - "deny": [] - } - }, - "allow-register-listener": { - "identifier": "allow-register-listener", - "description": "Enables the register_listener command without any pre-configured scope.", - "commands": { - "allow": [ - "register_listener" - ], - "deny": [] - } - }, - "allow-remove-data-store": { - "identifier": "allow-remove-data-store", - "description": "Enables the remove_data_store command without any pre-configured scope.", - "commands": { - "allow": [ - "remove_data_store" - ], - "deny": [] - } - }, - "allow-remove-listener": { - "identifier": "allow-remove-listener", - "description": "Enables the remove_listener command without any pre-configured scope.", - "commands": { - "allow": [ - "remove_listener" - ], - "deny": [] - } - }, - "allow-set-app-theme": { - "identifier": "allow-set-app-theme", - "description": "Enables the set_app_theme command without any pre-configured scope.", - "commands": { - "allow": [ - "set_app_theme" - ], - "deny": [] - } - }, - "allow-set-dock-visibility": { - "identifier": "allow-set-dock-visibility", - "description": "Enables the set_dock_visibility command without any pre-configured scope.", - "commands": { - "allow": [ - "set_dock_visibility" - ], - "deny": [] - } - }, - "allow-supports-multiple-windows": { - "identifier": "allow-supports-multiple-windows", - "description": "Enables the supports_multiple_windows command without any pre-configured scope.", - "commands": { - "allow": [ - "supports_multiple_windows" - ], - "deny": [] - } - }, - "allow-tauri-version": { - "identifier": "allow-tauri-version", - "description": "Enables the tauri_version command without any pre-configured scope.", - "commands": { - "allow": [ - "tauri_version" - ], - "deny": [] - } - }, - "allow-version": { - "identifier": "allow-version", - "description": "Enables the version command without any pre-configured scope.", - "commands": { - "allow": [ - "version" - ], - "deny": [] - } - }, - "deny-app-hide": { - "identifier": "deny-app-hide", - "description": "Denies the app_hide command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "app_hide" - ] - } - }, - "deny-app-show": { - "identifier": "deny-app-show", - "description": "Denies the app_show command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "app_show" - ] - } - }, - "deny-bundle-type": { - "identifier": "deny-bundle-type", - "description": "Denies the bundle_type command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "bundle_type" - ] - } - }, - "deny-default-window-icon": { - "identifier": "deny-default-window-icon", - "description": "Denies the default_window_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "default_window_icon" - ] - } - }, - "deny-fetch-data-store-identifiers": { - "identifier": "deny-fetch-data-store-identifiers", - "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "fetch_data_store_identifiers" - ] - } - }, - "deny-identifier": { - "identifier": "deny-identifier", - "description": "Denies the identifier command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "identifier" - ] - } - }, - "deny-name": { - "identifier": "deny-name", - "description": "Denies the name command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "name" - ] - } - }, - "deny-register-listener": { - "identifier": "deny-register-listener", - "description": "Denies the register_listener command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "register_listener" - ] - } - }, - "deny-remove-data-store": { - "identifier": "deny-remove-data-store", - "description": "Denies the remove_data_store command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove_data_store" - ] - } - }, - "deny-remove-listener": { - "identifier": "deny-remove-listener", - "description": "Denies the remove_listener command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove_listener" - ] - } - }, - "deny-set-app-theme": { - "identifier": "deny-set-app-theme", - "description": "Denies the set_app_theme command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_app_theme" - ] - } - }, - "deny-set-dock-visibility": { - "identifier": "deny-set-dock-visibility", - "description": "Denies the set_dock_visibility command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_dock_visibility" - ] - } - }, - "deny-supports-multiple-windows": { - "identifier": "deny-supports-multiple-windows", - "description": "Denies the supports_multiple_windows command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "supports_multiple_windows" - ] - } - }, - "deny-tauri-version": { - "identifier": "deny-tauri-version", - "description": "Denies the tauri_version command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "tauri_version" - ] - } - }, - "deny-version": { - "identifier": "deny-version", - "description": "Denies the version command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "version" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:event": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-listen", - "allow-unlisten", - "allow-emit", - "allow-emit-to" - ] - }, - "permissions": { - "allow-emit": { - "identifier": "allow-emit", - "description": "Enables the emit command without any pre-configured scope.", - "commands": { - "allow": [ - "emit" - ], - "deny": [] - } - }, - "allow-emit-to": { - "identifier": "allow-emit-to", - "description": "Enables the emit_to command without any pre-configured scope.", - "commands": { - "allow": [ - "emit_to" - ], - "deny": [] - } - }, - "allow-listen": { - "identifier": "allow-listen", - "description": "Enables the listen command without any pre-configured scope.", - "commands": { - "allow": [ - "listen" - ], - "deny": [] - } - }, - "allow-unlisten": { - "identifier": "allow-unlisten", - "description": "Enables the unlisten command without any pre-configured scope.", - "commands": { - "allow": [ - "unlisten" - ], - "deny": [] - } - }, - "deny-emit": { - "identifier": "deny-emit", - "description": "Denies the emit command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "emit" - ] - } - }, - "deny-emit-to": { - "identifier": "deny-emit-to", - "description": "Denies the emit_to command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "emit_to" - ] - } - }, - "deny-listen": { - "identifier": "deny-listen", - "description": "Denies the listen command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "listen" - ] - } - }, - "deny-unlisten": { - "identifier": "deny-unlisten", - "description": "Denies the unlisten command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "unlisten" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:image": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-new", - "allow-from-bytes", - "allow-from-path", - "allow-rgba", - "allow-size" - ] - }, - "permissions": { - "allow-from-bytes": { - "identifier": "allow-from-bytes", - "description": "Enables the from_bytes command without any pre-configured scope.", - "commands": { - "allow": [ - "from_bytes" - ], - "deny": [] - } - }, - "allow-from-path": { - "identifier": "allow-from-path", - "description": "Enables the from_path command without any pre-configured scope.", - "commands": { - "allow": [ - "from_path" - ], - "deny": [] - } - }, - "allow-new": { - "identifier": "allow-new", - "description": "Enables the new command without any pre-configured scope.", - "commands": { - "allow": [ - "new" - ], - "deny": [] - } - }, - "allow-rgba": { - "identifier": "allow-rgba", - "description": "Enables the rgba command without any pre-configured scope.", - "commands": { - "allow": [ - "rgba" - ], - "deny": [] - } - }, - "allow-size": { - "identifier": "allow-size", - "description": "Enables the size command without any pre-configured scope.", - "commands": { - "allow": [ - "size" - ], - "deny": [] - } - }, - "deny-from-bytes": { - "identifier": "deny-from-bytes", - "description": "Denies the from_bytes command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "from_bytes" - ] - } - }, - "deny-from-path": { - "identifier": "deny-from-path", - "description": "Denies the from_path command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "from_path" - ] - } - }, - "deny-new": { - "identifier": "deny-new", - "description": "Denies the new command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "new" - ] - } - }, - "deny-rgba": { - "identifier": "deny-rgba", - "description": "Denies the rgba command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "rgba" - ] - } - }, - "deny-size": { - "identifier": "deny-size", - "description": "Denies the size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "size" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:menu": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-new", - "allow-append", - "allow-prepend", - "allow-insert", - "allow-remove", - "allow-remove-at", - "allow-items", - "allow-get", - "allow-popup", - "allow-create-default", - "allow-set-as-app-menu", - "allow-set-as-window-menu", - "allow-text", - "allow-set-text", - "allow-is-enabled", - "allow-set-enabled", - "allow-set-accelerator", - "allow-set-as-windows-menu-for-nsapp", - "allow-set-as-help-menu-for-nsapp", - "allow-is-checked", - "allow-set-checked", - "allow-set-icon" - ] - }, - "permissions": { - "allow-append": { - "identifier": "allow-append", - "description": "Enables the append command without any pre-configured scope.", - "commands": { - "allow": [ - "append" - ], - "deny": [] - } - }, - "allow-create-default": { - "identifier": "allow-create-default", - "description": "Enables the create_default command without any pre-configured scope.", - "commands": { - "allow": [ - "create_default" - ], - "deny": [] - } - }, - "allow-get": { - "identifier": "allow-get", - "description": "Enables the get command without any pre-configured scope.", - "commands": { - "allow": [ - "get" - ], - "deny": [] - } - }, - "allow-insert": { - "identifier": "allow-insert", - "description": "Enables the insert command without any pre-configured scope.", - "commands": { - "allow": [ - "insert" - ], - "deny": [] - } - }, - "allow-is-checked": { - "identifier": "allow-is-checked", - "description": "Enables the is_checked command without any pre-configured scope.", - "commands": { - "allow": [ - "is_checked" - ], - "deny": [] - } - }, - "allow-is-enabled": { - "identifier": "allow-is-enabled", - "description": "Enables the is_enabled command without any pre-configured scope.", - "commands": { - "allow": [ - "is_enabled" - ], - "deny": [] - } - }, - "allow-items": { - "identifier": "allow-items", - "description": "Enables the items command without any pre-configured scope.", - "commands": { - "allow": [ - "items" - ], - "deny": [] - } - }, - "allow-new": { - "identifier": "allow-new", - "description": "Enables the new command without any pre-configured scope.", - "commands": { - "allow": [ - "new" - ], - "deny": [] - } - }, - "allow-popup": { - "identifier": "allow-popup", - "description": "Enables the popup command without any pre-configured scope.", - "commands": { - "allow": [ - "popup" - ], - "deny": [] - } - }, - "allow-prepend": { - "identifier": "allow-prepend", - "description": "Enables the prepend command without any pre-configured scope.", - "commands": { - "allow": [ - "prepend" - ], - "deny": [] - } - }, - "allow-remove": { - "identifier": "allow-remove", - "description": "Enables the remove command without any pre-configured scope.", - "commands": { - "allow": [ - "remove" - ], - "deny": [] - } - }, - "allow-remove-at": { - "identifier": "allow-remove-at", - "description": "Enables the remove_at command without any pre-configured scope.", - "commands": { - "allow": [ - "remove_at" - ], - "deny": [] - } - }, - "allow-set-accelerator": { - "identifier": "allow-set-accelerator", - "description": "Enables the set_accelerator command without any pre-configured scope.", - "commands": { - "allow": [ - "set_accelerator" - ], - "deny": [] - } - }, - "allow-set-as-app-menu": { - "identifier": "allow-set-as-app-menu", - "description": "Enables the set_as_app_menu command without any pre-configured scope.", - "commands": { - "allow": [ - "set_as_app_menu" - ], - "deny": [] - } - }, - "allow-set-as-help-menu-for-nsapp": { - "identifier": "allow-set-as-help-menu-for-nsapp", - "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", - "commands": { - "allow": [ - "set_as_help_menu_for_nsapp" - ], - "deny": [] - } - }, - "allow-set-as-window-menu": { - "identifier": "allow-set-as-window-menu", - "description": "Enables the set_as_window_menu command without any pre-configured scope.", - "commands": { - "allow": [ - "set_as_window_menu" - ], - "deny": [] - } - }, - "allow-set-as-windows-menu-for-nsapp": { - "identifier": "allow-set-as-windows-menu-for-nsapp", - "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", - "commands": { - "allow": [ - "set_as_windows_menu_for_nsapp" - ], - "deny": [] - } - }, - "allow-set-checked": { - "identifier": "allow-set-checked", - "description": "Enables the set_checked command without any pre-configured scope.", - "commands": { - "allow": [ - "set_checked" - ], - "deny": [] - } - }, - "allow-set-enabled": { - "identifier": "allow-set-enabled", - "description": "Enables the set_enabled command without any pre-configured scope.", - "commands": { - "allow": [ - "set_enabled" - ], - "deny": [] - } - }, - "allow-set-icon": { - "identifier": "allow-set-icon", - "description": "Enables the set_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "set_icon" - ], - "deny": [] - } - }, - "allow-set-text": { - "identifier": "allow-set-text", - "description": "Enables the set_text command without any pre-configured scope.", - "commands": { - "allow": [ - "set_text" - ], - "deny": [] - } - }, - "allow-text": { - "identifier": "allow-text", - "description": "Enables the text command without any pre-configured scope.", - "commands": { - "allow": [ - "text" - ], - "deny": [] - } - }, - "deny-append": { - "identifier": "deny-append", - "description": "Denies the append command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "append" - ] - } - }, - "deny-create-default": { - "identifier": "deny-create-default", - "description": "Denies the create_default command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "create_default" - ] - } - }, - "deny-get": { - "identifier": "deny-get", - "description": "Denies the get command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "get" - ] - } - }, - "deny-insert": { - "identifier": "deny-insert", - "description": "Denies the insert command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "insert" - ] - } - }, - "deny-is-checked": { - "identifier": "deny-is-checked", - "description": "Denies the is_checked command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_checked" - ] - } - }, - "deny-is-enabled": { - "identifier": "deny-is-enabled", - "description": "Denies the is_enabled command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_enabled" - ] - } - }, - "deny-items": { - "identifier": "deny-items", - "description": "Denies the items command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "items" - ] - } - }, - "deny-new": { - "identifier": "deny-new", - "description": "Denies the new command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "new" - ] - } - }, - "deny-popup": { - "identifier": "deny-popup", - "description": "Denies the popup command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "popup" - ] - } - }, - "deny-prepend": { - "identifier": "deny-prepend", - "description": "Denies the prepend command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "prepend" - ] - } - }, - "deny-remove": { - "identifier": "deny-remove", - "description": "Denies the remove command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove" - ] - } - }, - "deny-remove-at": { - "identifier": "deny-remove-at", - "description": "Denies the remove_at command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove_at" - ] - } - }, - "deny-set-accelerator": { - "identifier": "deny-set-accelerator", - "description": "Denies the set_accelerator command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_accelerator" - ] - } - }, - "deny-set-as-app-menu": { - "identifier": "deny-set-as-app-menu", - "description": "Denies the set_as_app_menu command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_as_app_menu" - ] - } - }, - "deny-set-as-help-menu-for-nsapp": { - "identifier": "deny-set-as-help-menu-for-nsapp", - "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_as_help_menu_for_nsapp" - ] - } - }, - "deny-set-as-window-menu": { - "identifier": "deny-set-as-window-menu", - "description": "Denies the set_as_window_menu command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_as_window_menu" - ] - } - }, - "deny-set-as-windows-menu-for-nsapp": { - "identifier": "deny-set-as-windows-menu-for-nsapp", - "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_as_windows_menu_for_nsapp" - ] - } - }, - "deny-set-checked": { - "identifier": "deny-set-checked", - "description": "Denies the set_checked command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_checked" - ] - } - }, - "deny-set-enabled": { - "identifier": "deny-set-enabled", - "description": "Denies the set_enabled command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_enabled" - ] - } - }, - "deny-set-icon": { - "identifier": "deny-set-icon", - "description": "Denies the set_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_icon" - ] - } - }, - "deny-set-text": { - "identifier": "deny-set-text", - "description": "Denies the set_text command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_text" - ] - } - }, - "deny-text": { - "identifier": "deny-text", - "description": "Denies the text command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "text" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:path": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-resolve-directory", - "allow-resolve", - "allow-normalize", - "allow-join", - "allow-dirname", - "allow-extname", - "allow-basename", - "allow-is-absolute" - ] - }, - "permissions": { - "allow-basename": { - "identifier": "allow-basename", - "description": "Enables the basename command without any pre-configured scope.", - "commands": { - "allow": [ - "basename" - ], - "deny": [] - } - }, - "allow-dirname": { - "identifier": "allow-dirname", - "description": "Enables the dirname command without any pre-configured scope.", - "commands": { - "allow": [ - "dirname" - ], - "deny": [] - } - }, - "allow-extname": { - "identifier": "allow-extname", - "description": "Enables the extname command without any pre-configured scope.", - "commands": { - "allow": [ - "extname" - ], - "deny": [] - } - }, - "allow-is-absolute": { - "identifier": "allow-is-absolute", - "description": "Enables the is_absolute command without any pre-configured scope.", - "commands": { - "allow": [ - "is_absolute" - ], - "deny": [] - } - }, - "allow-join": { - "identifier": "allow-join", - "description": "Enables the join command without any pre-configured scope.", - "commands": { - "allow": [ - "join" - ], - "deny": [] - } - }, - "allow-normalize": { - "identifier": "allow-normalize", - "description": "Enables the normalize command without any pre-configured scope.", - "commands": { - "allow": [ - "normalize" - ], - "deny": [] - } - }, - "allow-resolve": { - "identifier": "allow-resolve", - "description": "Enables the resolve command without any pre-configured scope.", - "commands": { - "allow": [ - "resolve" - ], - "deny": [] - } - }, - "allow-resolve-directory": { - "identifier": "allow-resolve-directory", - "description": "Enables the resolve_directory command without any pre-configured scope.", - "commands": { - "allow": [ - "resolve_directory" - ], - "deny": [] - } - }, - "deny-basename": { - "identifier": "deny-basename", - "description": "Denies the basename command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "basename" - ] - } - }, - "deny-dirname": { - "identifier": "deny-dirname", - "description": "Denies the dirname command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "dirname" - ] - } - }, - "deny-extname": { - "identifier": "deny-extname", - "description": "Denies the extname command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "extname" - ] - } - }, - "deny-is-absolute": { - "identifier": "deny-is-absolute", - "description": "Denies the is_absolute command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_absolute" - ] - } - }, - "deny-join": { - "identifier": "deny-join", - "description": "Denies the join command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "join" - ] - } - }, - "deny-normalize": { - "identifier": "deny-normalize", - "description": "Denies the normalize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "normalize" - ] - } - }, - "deny-resolve": { - "identifier": "deny-resolve", - "description": "Denies the resolve command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "resolve" - ] - } - }, - "deny-resolve-directory": { - "identifier": "deny-resolve-directory", - "description": "Denies the resolve_directory command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "resolve_directory" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:resources": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-close" - ] - }, - "permissions": { - "allow-close": { - "identifier": "allow-close", - "description": "Enables the close command without any pre-configured scope.", - "commands": { - "allow": [ - "close" - ], - "deny": [] - } - }, - "deny-close": { - "identifier": "deny-close", - "description": "Denies the close command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "close" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:tray": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin, which enables all commands.", - "permissions": [ - "allow-new", - "allow-get-by-id", - "allow-remove-by-id", - "allow-set-icon", - "allow-set-menu", - "allow-set-tooltip", - "allow-set-title", - "allow-set-visible", - "allow-set-temp-dir-path", - "allow-set-icon-as-template", - "allow-set-icon-with-as-template", - "allow-set-show-menu-on-left-click" - ] - }, - "permissions": { - "allow-get-by-id": { - "identifier": "allow-get-by-id", - "description": "Enables the get_by_id command without any pre-configured scope.", - "commands": { - "allow": [ - "get_by_id" - ], - "deny": [] - } - }, - "allow-new": { - "identifier": "allow-new", - "description": "Enables the new command without any pre-configured scope.", - "commands": { - "allow": [ - "new" - ], - "deny": [] - } - }, - "allow-remove-by-id": { - "identifier": "allow-remove-by-id", - "description": "Enables the remove_by_id command without any pre-configured scope.", - "commands": { - "allow": [ - "remove_by_id" - ], - "deny": [] - } - }, - "allow-set-icon": { - "identifier": "allow-set-icon", - "description": "Enables the set_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "set_icon" - ], - "deny": [] - } - }, - "allow-set-icon-as-template": { - "identifier": "allow-set-icon-as-template", - "description": "Enables the set_icon_as_template command without any pre-configured scope.", - "commands": { - "allow": [ - "set_icon_as_template" - ], - "deny": [] - } - }, - "allow-set-icon-with-as-template": { - "identifier": "allow-set-icon-with-as-template", - "description": "Enables the set_icon_with_as_template command without any pre-configured scope.", - "commands": { - "allow": [ - "set_icon_with_as_template" - ], - "deny": [] - } - }, - "allow-set-menu": { - "identifier": "allow-set-menu", - "description": "Enables the set_menu command without any pre-configured scope.", - "commands": { - "allow": [ - "set_menu" - ], - "deny": [] - } - }, - "allow-set-show-menu-on-left-click": { - "identifier": "allow-set-show-menu-on-left-click", - "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", - "commands": { - "allow": [ - "set_show_menu_on_left_click" - ], - "deny": [] - } - }, - "allow-set-temp-dir-path": { - "identifier": "allow-set-temp-dir-path", - "description": "Enables the set_temp_dir_path command without any pre-configured scope.", - "commands": { - "allow": [ - "set_temp_dir_path" - ], - "deny": [] - } - }, - "allow-set-title": { - "identifier": "allow-set-title", - "description": "Enables the set_title command without any pre-configured scope.", - "commands": { - "allow": [ - "set_title" - ], - "deny": [] - } - }, - "allow-set-tooltip": { - "identifier": "allow-set-tooltip", - "description": "Enables the set_tooltip command without any pre-configured scope.", - "commands": { - "allow": [ - "set_tooltip" - ], - "deny": [] - } - }, - "allow-set-visible": { - "identifier": "allow-set-visible", - "description": "Enables the set_visible command without any pre-configured scope.", - "commands": { - "allow": [ - "set_visible" - ], - "deny": [] - } - }, - "deny-get-by-id": { - "identifier": "deny-get-by-id", - "description": "Denies the get_by_id command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "get_by_id" - ] - } - }, - "deny-new": { - "identifier": "deny-new", - "description": "Denies the new command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "new" - ] - } - }, - "deny-remove-by-id": { - "identifier": "deny-remove-by-id", - "description": "Denies the remove_by_id command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove_by_id" - ] - } - }, - "deny-set-icon": { - "identifier": "deny-set-icon", - "description": "Denies the set_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_icon" - ] - } - }, - "deny-set-icon-as-template": { - "identifier": "deny-set-icon-as-template", - "description": "Denies the set_icon_as_template command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_icon_as_template" - ] - } - }, - "deny-set-icon-with-as-template": { - "identifier": "deny-set-icon-with-as-template", - "description": "Denies the set_icon_with_as_template command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_icon_with_as_template" - ] - } - }, - "deny-set-menu": { - "identifier": "deny-set-menu", - "description": "Denies the set_menu command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_menu" - ] - } - }, - "deny-set-show-menu-on-left-click": { - "identifier": "deny-set-show-menu-on-left-click", - "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_show_menu_on_left_click" - ] - } - }, - "deny-set-temp-dir-path": { - "identifier": "deny-set-temp-dir-path", - "description": "Denies the set_temp_dir_path command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_temp_dir_path" - ] - } - }, - "deny-set-title": { - "identifier": "deny-set-title", - "description": "Denies the set_title command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_title" - ] - } - }, - "deny-set-tooltip": { - "identifier": "deny-set-tooltip", - "description": "Denies the set_tooltip command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_tooltip" - ] - } - }, - "deny-set-visible": { - "identifier": "deny-set-visible", - "description": "Denies the set_visible command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_visible" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:webview": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin.", - "permissions": [ - "allow-get-all-webviews", - "allow-webview-position", - "allow-webview-size", - "allow-internal-toggle-devtools" - ] - }, - "permissions": { - "allow-clear-all-browsing-data": { - "identifier": "allow-clear-all-browsing-data", - "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", - "commands": { - "allow": [ - "clear_all_browsing_data" - ], - "deny": [] - } - }, - "allow-create-webview": { - "identifier": "allow-create-webview", - "description": "Enables the create_webview command without any pre-configured scope.", - "commands": { - "allow": [ - "create_webview" - ], - "deny": [] - } - }, - "allow-create-webview-window": { - "identifier": "allow-create-webview-window", - "description": "Enables the create_webview_window command without any pre-configured scope.", - "commands": { - "allow": [ - "create_webview_window" - ], - "deny": [] - } - }, - "allow-get-all-webviews": { - "identifier": "allow-get-all-webviews", - "description": "Enables the get_all_webviews command without any pre-configured scope.", - "commands": { - "allow": [ - "get_all_webviews" - ], - "deny": [] - } - }, - "allow-internal-toggle-devtools": { - "identifier": "allow-internal-toggle-devtools", - "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", - "commands": { - "allow": [ - "internal_toggle_devtools" - ], - "deny": [] - } - }, - "allow-print": { - "identifier": "allow-print", - "description": "Enables the print command without any pre-configured scope.", - "commands": { - "allow": [ - "print" - ], - "deny": [] - } - }, - "allow-reparent": { - "identifier": "allow-reparent", - "description": "Enables the reparent command without any pre-configured scope.", - "commands": { - "allow": [ - "reparent" - ], - "deny": [] - } - }, - "allow-set-webview-auto-resize": { - "identifier": "allow-set-webview-auto-resize", - "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_auto_resize" - ], - "deny": [] - } - }, - "allow-set-webview-background-color": { - "identifier": "allow-set-webview-background-color", - "description": "Enables the set_webview_background_color command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_background_color" - ], - "deny": [] - } - }, - "allow-set-webview-focus": { - "identifier": "allow-set-webview-focus", - "description": "Enables the set_webview_focus command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_focus" - ], - "deny": [] - } - }, - "allow-set-webview-position": { - "identifier": "allow-set-webview-position", - "description": "Enables the set_webview_position command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_position" - ], - "deny": [] - } - }, - "allow-set-webview-size": { - "identifier": "allow-set-webview-size", - "description": "Enables the set_webview_size command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_size" - ], - "deny": [] - } - }, - "allow-set-webview-zoom": { - "identifier": "allow-set-webview-zoom", - "description": "Enables the set_webview_zoom command without any pre-configured scope.", - "commands": { - "allow": [ - "set_webview_zoom" - ], - "deny": [] - } - }, - "allow-webview-close": { - "identifier": "allow-webview-close", - "description": "Enables the webview_close command without any pre-configured scope.", - "commands": { - "allow": [ - "webview_close" - ], - "deny": [] - } - }, - "allow-webview-hide": { - "identifier": "allow-webview-hide", - "description": "Enables the webview_hide command without any pre-configured scope.", - "commands": { - "allow": [ - "webview_hide" - ], - "deny": [] - } - }, - "allow-webview-position": { - "identifier": "allow-webview-position", - "description": "Enables the webview_position command without any pre-configured scope.", - "commands": { - "allow": [ - "webview_position" - ], - "deny": [] - } - }, - "allow-webview-show": { - "identifier": "allow-webview-show", - "description": "Enables the webview_show command without any pre-configured scope.", - "commands": { - "allow": [ - "webview_show" - ], - "deny": [] - } - }, - "allow-webview-size": { - "identifier": "allow-webview-size", - "description": "Enables the webview_size command without any pre-configured scope.", - "commands": { - "allow": [ - "webview_size" - ], - "deny": [] - } - }, - "deny-clear-all-browsing-data": { - "identifier": "deny-clear-all-browsing-data", - "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "clear_all_browsing_data" - ] - } - }, - "deny-create-webview": { - "identifier": "deny-create-webview", - "description": "Denies the create_webview command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "create_webview" - ] - } - }, - "deny-create-webview-window": { - "identifier": "deny-create-webview-window", - "description": "Denies the create_webview_window command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "create_webview_window" - ] - } - }, - "deny-get-all-webviews": { - "identifier": "deny-get-all-webviews", - "description": "Denies the get_all_webviews command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "get_all_webviews" - ] - } - }, - "deny-internal-toggle-devtools": { - "identifier": "deny-internal-toggle-devtools", - "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "internal_toggle_devtools" - ] - } - }, - "deny-print": { - "identifier": "deny-print", - "description": "Denies the print command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "print" - ] - } - }, - "deny-reparent": { - "identifier": "deny-reparent", - "description": "Denies the reparent command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "reparent" - ] - } - }, - "deny-set-webview-auto-resize": { - "identifier": "deny-set-webview-auto-resize", - "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_auto_resize" - ] - } - }, - "deny-set-webview-background-color": { - "identifier": "deny-set-webview-background-color", - "description": "Denies the set_webview_background_color command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_background_color" - ] - } - }, - "deny-set-webview-focus": { - "identifier": "deny-set-webview-focus", - "description": "Denies the set_webview_focus command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_focus" - ] - } - }, - "deny-set-webview-position": { - "identifier": "deny-set-webview-position", - "description": "Denies the set_webview_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_position" - ] - } - }, - "deny-set-webview-size": { - "identifier": "deny-set-webview-size", - "description": "Denies the set_webview_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_size" - ] - } - }, - "deny-set-webview-zoom": { - "identifier": "deny-set-webview-zoom", - "description": "Denies the set_webview_zoom command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_webview_zoom" - ] - } - }, - "deny-webview-close": { - "identifier": "deny-webview-close", - "description": "Denies the webview_close command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "webview_close" - ] - } - }, - "deny-webview-hide": { - "identifier": "deny-webview-hide", - "description": "Denies the webview_hide command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "webview_hide" - ] - } - }, - "deny-webview-position": { - "identifier": "deny-webview-position", - "description": "Denies the webview_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "webview_position" - ] - } - }, - "deny-webview-show": { - "identifier": "deny-webview-show", - "description": "Denies the webview_show command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "webview_show" - ] - } - }, - "deny-webview-size": { - "identifier": "deny-webview-size", - "description": "Denies the webview_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "webview_size" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "core:window": { - "default_permission": { - "identifier": "default", - "description": "Default permissions for the plugin.", - "permissions": [ - "allow-get-all-windows", - "allow-scale-factor", - "allow-inner-position", - "allow-outer-position", - "allow-inner-size", - "allow-outer-size", - "allow-is-fullscreen", - "allow-is-minimized", - "allow-is-maximized", - "allow-is-focused", - "allow-is-decorated", - "allow-is-resizable", - "allow-is-maximizable", - "allow-is-minimizable", - "allow-is-closable", - "allow-is-visible", - "allow-is-enabled", - "allow-title", - "allow-current-monitor", - "allow-primary-monitor", - "allow-monitor-from-point", - "allow-available-monitors", - "allow-cursor-position", - "allow-theme", - "allow-is-always-on-top", - "allow-activity-name", - "allow-scene-identifier", - "allow-internal-toggle-maximize" - ] - }, - "permissions": { - "allow-activity-name": { - "identifier": "allow-activity-name", - "description": "Enables the activity_name command without any pre-configured scope.", - "commands": { - "allow": [ - "activity_name" - ], - "deny": [] - } - }, - "allow-available-monitors": { - "identifier": "allow-available-monitors", - "description": "Enables the available_monitors command without any pre-configured scope.", - "commands": { - "allow": [ - "available_monitors" - ], - "deny": [] - } - }, - "allow-center": { - "identifier": "allow-center", - "description": "Enables the center command without any pre-configured scope.", - "commands": { - "allow": [ - "center" - ], - "deny": [] - } - }, - "allow-close": { - "identifier": "allow-close", - "description": "Enables the close command without any pre-configured scope.", - "commands": { - "allow": [ - "close" - ], - "deny": [] - } - }, - "allow-create": { - "identifier": "allow-create", - "description": "Enables the create command without any pre-configured scope.", - "commands": { - "allow": [ - "create" - ], - "deny": [] - } - }, - "allow-current-monitor": { - "identifier": "allow-current-monitor", - "description": "Enables the current_monitor command without any pre-configured scope.", - "commands": { - "allow": [ - "current_monitor" - ], - "deny": [] - } - }, - "allow-cursor-position": { - "identifier": "allow-cursor-position", - "description": "Enables the cursor_position command without any pre-configured scope.", - "commands": { - "allow": [ - "cursor_position" - ], - "deny": [] - } - }, - "allow-destroy": { - "identifier": "allow-destroy", - "description": "Enables the destroy command without any pre-configured scope.", - "commands": { - "allow": [ - "destroy" - ], - "deny": [] - } - }, - "allow-get-all-windows": { - "identifier": "allow-get-all-windows", - "description": "Enables the get_all_windows command without any pre-configured scope.", - "commands": { - "allow": [ - "get_all_windows" - ], - "deny": [] - } - }, - "allow-hide": { - "identifier": "allow-hide", - "description": "Enables the hide command without any pre-configured scope.", - "commands": { - "allow": [ - "hide" - ], - "deny": [] - } - }, - "allow-inner-position": { - "identifier": "allow-inner-position", - "description": "Enables the inner_position command without any pre-configured scope.", - "commands": { - "allow": [ - "inner_position" - ], - "deny": [] - } - }, - "allow-inner-size": { - "identifier": "allow-inner-size", - "description": "Enables the inner_size command without any pre-configured scope.", - "commands": { - "allow": [ - "inner_size" - ], - "deny": [] - } - }, - "allow-internal-toggle-maximize": { - "identifier": "allow-internal-toggle-maximize", - "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", - "commands": { - "allow": [ - "internal_toggle_maximize" - ], - "deny": [] - } - }, - "allow-is-always-on-top": { - "identifier": "allow-is-always-on-top", - "description": "Enables the is_always_on_top command without any pre-configured scope.", - "commands": { - "allow": [ - "is_always_on_top" - ], - "deny": [] - } - }, - "allow-is-closable": { - "identifier": "allow-is-closable", - "description": "Enables the is_closable command without any pre-configured scope.", - "commands": { - "allow": [ - "is_closable" - ], - "deny": [] - } - }, - "allow-is-decorated": { - "identifier": "allow-is-decorated", - "description": "Enables the is_decorated command without any pre-configured scope.", - "commands": { - "allow": [ - "is_decorated" - ], - "deny": [] - } - }, - "allow-is-enabled": { - "identifier": "allow-is-enabled", - "description": "Enables the is_enabled command without any pre-configured scope.", - "commands": { - "allow": [ - "is_enabled" - ], - "deny": [] - } - }, - "allow-is-focused": { - "identifier": "allow-is-focused", - "description": "Enables the is_focused command without any pre-configured scope.", - "commands": { - "allow": [ - "is_focused" - ], - "deny": [] - } - }, - "allow-is-fullscreen": { - "identifier": "allow-is-fullscreen", - "description": "Enables the is_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [ - "is_fullscreen" - ], - "deny": [] - } - }, - "allow-is-maximizable": { - "identifier": "allow-is-maximizable", - "description": "Enables the is_maximizable command without any pre-configured scope.", - "commands": { - "allow": [ - "is_maximizable" - ], - "deny": [] - } - }, - "allow-is-maximized": { - "identifier": "allow-is-maximized", - "description": "Enables the is_maximized command without any pre-configured scope.", - "commands": { - "allow": [ - "is_maximized" - ], - "deny": [] - } - }, - "allow-is-minimizable": { - "identifier": "allow-is-minimizable", - "description": "Enables the is_minimizable command without any pre-configured scope.", - "commands": { - "allow": [ - "is_minimizable" - ], - "deny": [] - } - }, - "allow-is-minimized": { - "identifier": "allow-is-minimized", - "description": "Enables the is_minimized command without any pre-configured scope.", - "commands": { - "allow": [ - "is_minimized" - ], - "deny": [] - } - }, - "allow-is-resizable": { - "identifier": "allow-is-resizable", - "description": "Enables the is_resizable command without any pre-configured scope.", - "commands": { - "allow": [ - "is_resizable" - ], - "deny": [] - } - }, - "allow-is-visible": { - "identifier": "allow-is-visible", - "description": "Enables the is_visible command without any pre-configured scope.", - "commands": { - "allow": [ - "is_visible" - ], - "deny": [] - } - }, - "allow-maximize": { - "identifier": "allow-maximize", - "description": "Enables the maximize command without any pre-configured scope.", - "commands": { - "allow": [ - "maximize" - ], - "deny": [] - } - }, - "allow-minimize": { - "identifier": "allow-minimize", - "description": "Enables the minimize command without any pre-configured scope.", - "commands": { - "allow": [ - "minimize" - ], - "deny": [] - } - }, - "allow-monitor-from-point": { - "identifier": "allow-monitor-from-point", - "description": "Enables the monitor_from_point command without any pre-configured scope.", - "commands": { - "allow": [ - "monitor_from_point" - ], - "deny": [] - } - }, - "allow-outer-position": { - "identifier": "allow-outer-position", - "description": "Enables the outer_position command without any pre-configured scope.", - "commands": { - "allow": [ - "outer_position" - ], - "deny": [] - } - }, - "allow-outer-size": { - "identifier": "allow-outer-size", - "description": "Enables the outer_size command without any pre-configured scope.", - "commands": { - "allow": [ - "outer_size" - ], - "deny": [] - } - }, - "allow-primary-monitor": { - "identifier": "allow-primary-monitor", - "description": "Enables the primary_monitor command without any pre-configured scope.", - "commands": { - "allow": [ - "primary_monitor" - ], - "deny": [] - } - }, - "allow-request-user-attention": { - "identifier": "allow-request-user-attention", - "description": "Enables the request_user_attention command without any pre-configured scope.", - "commands": { - "allow": [ - "request_user_attention" - ], - "deny": [] - } - }, - "allow-scale-factor": { - "identifier": "allow-scale-factor", - "description": "Enables the scale_factor command without any pre-configured scope.", - "commands": { - "allow": [ - "scale_factor" - ], - "deny": [] - } - }, - "allow-scene-identifier": { - "identifier": "allow-scene-identifier", - "description": "Enables the scene_identifier command without any pre-configured scope.", - "commands": { - "allow": [ - "scene_identifier" - ], - "deny": [] - } - }, - "allow-set-always-on-bottom": { - "identifier": "allow-set-always-on-bottom", - "description": "Enables the set_always_on_bottom command without any pre-configured scope.", - "commands": { - "allow": [ - "set_always_on_bottom" - ], - "deny": [] - } - }, - "allow-set-always-on-top": { - "identifier": "allow-set-always-on-top", - "description": "Enables the set_always_on_top command without any pre-configured scope.", - "commands": { - "allow": [ - "set_always_on_top" - ], - "deny": [] - } - }, - "allow-set-background-color": { - "identifier": "allow-set-background-color", - "description": "Enables the set_background_color command without any pre-configured scope.", - "commands": { - "allow": [ - "set_background_color" - ], - "deny": [] - } - }, - "allow-set-badge-count": { - "identifier": "allow-set-badge-count", - "description": "Enables the set_badge_count command without any pre-configured scope.", - "commands": { - "allow": [ - "set_badge_count" - ], - "deny": [] - } - }, - "allow-set-badge-label": { - "identifier": "allow-set-badge-label", - "description": "Enables the set_badge_label command without any pre-configured scope.", - "commands": { - "allow": [ - "set_badge_label" - ], - "deny": [] - } - }, - "allow-set-closable": { - "identifier": "allow-set-closable", - "description": "Enables the set_closable command without any pre-configured scope.", - "commands": { - "allow": [ - "set_closable" - ], - "deny": [] - } - }, - "allow-set-content-protected": { - "identifier": "allow-set-content-protected", - "description": "Enables the set_content_protected command without any pre-configured scope.", - "commands": { - "allow": [ - "set_content_protected" - ], - "deny": [] - } - }, - "allow-set-cursor-grab": { - "identifier": "allow-set-cursor-grab", - "description": "Enables the set_cursor_grab command without any pre-configured scope.", - "commands": { - "allow": [ - "set_cursor_grab" - ], - "deny": [] - } - }, - "allow-set-cursor-icon": { - "identifier": "allow-set-cursor-icon", - "description": "Enables the set_cursor_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "set_cursor_icon" - ], - "deny": [] - } - }, - "allow-set-cursor-position": { - "identifier": "allow-set-cursor-position", - "description": "Enables the set_cursor_position command without any pre-configured scope.", - "commands": { - "allow": [ - "set_cursor_position" - ], - "deny": [] - } - }, - "allow-set-cursor-visible": { - "identifier": "allow-set-cursor-visible", - "description": "Enables the set_cursor_visible command without any pre-configured scope.", - "commands": { - "allow": [ - "set_cursor_visible" - ], - "deny": [] - } - }, - "allow-set-decorations": { - "identifier": "allow-set-decorations", - "description": "Enables the set_decorations command without any pre-configured scope.", - "commands": { - "allow": [ - "set_decorations" - ], - "deny": [] - } - }, - "allow-set-effects": { - "identifier": "allow-set-effects", - "description": "Enables the set_effects command without any pre-configured scope.", - "commands": { - "allow": [ - "set_effects" - ], - "deny": [] - } - }, - "allow-set-enabled": { - "identifier": "allow-set-enabled", - "description": "Enables the set_enabled command without any pre-configured scope.", - "commands": { - "allow": [ - "set_enabled" - ], - "deny": [] - } - }, - "allow-set-focus": { - "identifier": "allow-set-focus", - "description": "Enables the set_focus command without any pre-configured scope.", - "commands": { - "allow": [ - "set_focus" - ], - "deny": [] - } - }, - "allow-set-focusable": { - "identifier": "allow-set-focusable", - "description": "Enables the set_focusable command without any pre-configured scope.", - "commands": { - "allow": [ - "set_focusable" - ], - "deny": [] - } - }, - "allow-set-fullscreen": { - "identifier": "allow-set-fullscreen", - "description": "Enables the set_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [ - "set_fullscreen" - ], - "deny": [] - } - }, - "allow-set-icon": { - "identifier": "allow-set-icon", - "description": "Enables the set_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "set_icon" - ], - "deny": [] - } - }, - "allow-set-ignore-cursor-events": { - "identifier": "allow-set-ignore-cursor-events", - "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", - "commands": { - "allow": [ - "set_ignore_cursor_events" - ], - "deny": [] - } - }, - "allow-set-max-size": { - "identifier": "allow-set-max-size", - "description": "Enables the set_max_size command without any pre-configured scope.", - "commands": { - "allow": [ - "set_max_size" - ], - "deny": [] - } - }, - "allow-set-maximizable": { - "identifier": "allow-set-maximizable", - "description": "Enables the set_maximizable command without any pre-configured scope.", - "commands": { - "allow": [ - "set_maximizable" - ], - "deny": [] - } - }, - "allow-set-min-size": { - "identifier": "allow-set-min-size", - "description": "Enables the set_min_size command without any pre-configured scope.", - "commands": { - "allow": [ - "set_min_size" - ], - "deny": [] - } - }, - "allow-set-minimizable": { - "identifier": "allow-set-minimizable", - "description": "Enables the set_minimizable command without any pre-configured scope.", - "commands": { - "allow": [ - "set_minimizable" - ], - "deny": [] - } - }, - "allow-set-overlay-icon": { - "identifier": "allow-set-overlay-icon", - "description": "Enables the set_overlay_icon command without any pre-configured scope.", - "commands": { - "allow": [ - "set_overlay_icon" - ], - "deny": [] - } - }, - "allow-set-position": { - "identifier": "allow-set-position", - "description": "Enables the set_position command without any pre-configured scope.", - "commands": { - "allow": [ - "set_position" - ], - "deny": [] - } - }, - "allow-set-progress-bar": { - "identifier": "allow-set-progress-bar", - "description": "Enables the set_progress_bar command without any pre-configured scope.", - "commands": { - "allow": [ - "set_progress_bar" - ], - "deny": [] - } - }, - "allow-set-resizable": { - "identifier": "allow-set-resizable", - "description": "Enables the set_resizable command without any pre-configured scope.", - "commands": { - "allow": [ - "set_resizable" - ], - "deny": [] - } - }, - "allow-set-shadow": { - "identifier": "allow-set-shadow", - "description": "Enables the set_shadow command without any pre-configured scope.", - "commands": { - "allow": [ - "set_shadow" - ], - "deny": [] - } - }, - "allow-set-simple-fullscreen": { - "identifier": "allow-set-simple-fullscreen", - "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [ - "set_simple_fullscreen" - ], - "deny": [] - } - }, - "allow-set-size": { - "identifier": "allow-set-size", - "description": "Enables the set_size command without any pre-configured scope.", - "commands": { - "allow": [ - "set_size" - ], - "deny": [] - } - }, - "allow-set-size-constraints": { - "identifier": "allow-set-size-constraints", - "description": "Enables the set_size_constraints command without any pre-configured scope.", - "commands": { - "allow": [ - "set_size_constraints" - ], - "deny": [] - } - }, - "allow-set-skip-taskbar": { - "identifier": "allow-set-skip-taskbar", - "description": "Enables the set_skip_taskbar command without any pre-configured scope.", - "commands": { - "allow": [ - "set_skip_taskbar" - ], - "deny": [] - } - }, - "allow-set-theme": { - "identifier": "allow-set-theme", - "description": "Enables the set_theme command without any pre-configured scope.", - "commands": { - "allow": [ - "set_theme" - ], - "deny": [] - } - }, - "allow-set-title": { - "identifier": "allow-set-title", - "description": "Enables the set_title command without any pre-configured scope.", - "commands": { - "allow": [ - "set_title" - ], - "deny": [] - } - }, - "allow-set-title-bar-style": { - "identifier": "allow-set-title-bar-style", - "description": "Enables the set_title_bar_style command without any pre-configured scope.", - "commands": { - "allow": [ - "set_title_bar_style" - ], - "deny": [] - } - }, - "allow-set-visible-on-all-workspaces": { - "identifier": "allow-set-visible-on-all-workspaces", - "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", - "commands": { - "allow": [ - "set_visible_on_all_workspaces" - ], - "deny": [] - } - }, - "allow-show": { - "identifier": "allow-show", - "description": "Enables the show command without any pre-configured scope.", - "commands": { - "allow": [ - "show" - ], - "deny": [] - } - }, - "allow-start-dragging": { - "identifier": "allow-start-dragging", - "description": "Enables the start_dragging command without any pre-configured scope.", - "commands": { - "allow": [ - "start_dragging" - ], - "deny": [] - } - }, - "allow-start-resize-dragging": { - "identifier": "allow-start-resize-dragging", - "description": "Enables the start_resize_dragging command without any pre-configured scope.", - "commands": { - "allow": [ - "start_resize_dragging" - ], - "deny": [] - } - }, - "allow-theme": { - "identifier": "allow-theme", - "description": "Enables the theme command without any pre-configured scope.", - "commands": { - "allow": [ - "theme" - ], - "deny": [] - } - }, - "allow-title": { - "identifier": "allow-title", - "description": "Enables the title command without any pre-configured scope.", - "commands": { - "allow": [ - "title" - ], - "deny": [] - } - }, - "allow-toggle-maximize": { - "identifier": "allow-toggle-maximize", - "description": "Enables the toggle_maximize command without any pre-configured scope.", - "commands": { - "allow": [ - "toggle_maximize" - ], - "deny": [] - } - }, - "allow-unmaximize": { - "identifier": "allow-unmaximize", - "description": "Enables the unmaximize command without any pre-configured scope.", - "commands": { - "allow": [ - "unmaximize" - ], - "deny": [] - } - }, - "allow-unminimize": { - "identifier": "allow-unminimize", - "description": "Enables the unminimize command without any pre-configured scope.", - "commands": { - "allow": [ - "unminimize" - ], - "deny": [] - } - }, - "deny-activity-name": { - "identifier": "deny-activity-name", - "description": "Denies the activity_name command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "activity_name" - ] - } - }, - "deny-available-monitors": { - "identifier": "deny-available-monitors", - "description": "Denies the available_monitors command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "available_monitors" - ] - } - }, - "deny-center": { - "identifier": "deny-center", - "description": "Denies the center command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "center" - ] - } - }, - "deny-close": { - "identifier": "deny-close", - "description": "Denies the close command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "close" - ] - } - }, - "deny-create": { - "identifier": "deny-create", - "description": "Denies the create command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "create" - ] - } - }, - "deny-current-monitor": { - "identifier": "deny-current-monitor", - "description": "Denies the current_monitor command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "current_monitor" - ] - } - }, - "deny-cursor-position": { - "identifier": "deny-cursor-position", - "description": "Denies the cursor_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "cursor_position" - ] - } - }, - "deny-destroy": { - "identifier": "deny-destroy", - "description": "Denies the destroy command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "destroy" - ] - } - }, - "deny-get-all-windows": { - "identifier": "deny-get-all-windows", - "description": "Denies the get_all_windows command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "get_all_windows" - ] - } - }, - "deny-hide": { - "identifier": "deny-hide", - "description": "Denies the hide command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "hide" - ] - } - }, - "deny-inner-position": { - "identifier": "deny-inner-position", - "description": "Denies the inner_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "inner_position" - ] - } - }, - "deny-inner-size": { - "identifier": "deny-inner-size", - "description": "Denies the inner_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "inner_size" - ] - } - }, - "deny-internal-toggle-maximize": { - "identifier": "deny-internal-toggle-maximize", - "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "internal_toggle_maximize" - ] - } - }, - "deny-is-always-on-top": { - "identifier": "deny-is-always-on-top", - "description": "Denies the is_always_on_top command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_always_on_top" - ] - } - }, - "deny-is-closable": { - "identifier": "deny-is-closable", - "description": "Denies the is_closable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_closable" - ] - } - }, - "deny-is-decorated": { - "identifier": "deny-is-decorated", - "description": "Denies the is_decorated command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_decorated" - ] - } - }, - "deny-is-enabled": { - "identifier": "deny-is-enabled", - "description": "Denies the is_enabled command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_enabled" - ] - } - }, - "deny-is-focused": { - "identifier": "deny-is-focused", - "description": "Denies the is_focused command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_focused" - ] - } - }, - "deny-is-fullscreen": { - "identifier": "deny-is-fullscreen", - "description": "Denies the is_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_fullscreen" - ] - } - }, - "deny-is-maximizable": { - "identifier": "deny-is-maximizable", - "description": "Denies the is_maximizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_maximizable" - ] - } - }, - "deny-is-maximized": { - "identifier": "deny-is-maximized", - "description": "Denies the is_maximized command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_maximized" - ] - } - }, - "deny-is-minimizable": { - "identifier": "deny-is-minimizable", - "description": "Denies the is_minimizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_minimizable" - ] - } - }, - "deny-is-minimized": { - "identifier": "deny-is-minimized", - "description": "Denies the is_minimized command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_minimized" - ] - } - }, - "deny-is-resizable": { - "identifier": "deny-is-resizable", - "description": "Denies the is_resizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_resizable" - ] - } - }, - "deny-is-visible": { - "identifier": "deny-is-visible", - "description": "Denies the is_visible command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "is_visible" - ] - } - }, - "deny-maximize": { - "identifier": "deny-maximize", - "description": "Denies the maximize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "maximize" - ] - } - }, - "deny-minimize": { - "identifier": "deny-minimize", - "description": "Denies the minimize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "minimize" - ] - } - }, - "deny-monitor-from-point": { - "identifier": "deny-monitor-from-point", - "description": "Denies the monitor_from_point command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "monitor_from_point" - ] - } - }, - "deny-outer-position": { - "identifier": "deny-outer-position", - "description": "Denies the outer_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "outer_position" - ] - } - }, - "deny-outer-size": { - "identifier": "deny-outer-size", - "description": "Denies the outer_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "outer_size" - ] - } - }, - "deny-primary-monitor": { - "identifier": "deny-primary-monitor", - "description": "Denies the primary_monitor command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "primary_monitor" - ] - } - }, - "deny-request-user-attention": { - "identifier": "deny-request-user-attention", - "description": "Denies the request_user_attention command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "request_user_attention" - ] - } - }, - "deny-scale-factor": { - "identifier": "deny-scale-factor", - "description": "Denies the scale_factor command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "scale_factor" - ] - } - }, - "deny-scene-identifier": { - "identifier": "deny-scene-identifier", - "description": "Denies the scene_identifier command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "scene_identifier" - ] - } - }, - "deny-set-always-on-bottom": { - "identifier": "deny-set-always-on-bottom", - "description": "Denies the set_always_on_bottom command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_always_on_bottom" - ] - } - }, - "deny-set-always-on-top": { - "identifier": "deny-set-always-on-top", - "description": "Denies the set_always_on_top command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_always_on_top" - ] - } - }, - "deny-set-background-color": { - "identifier": "deny-set-background-color", - "description": "Denies the set_background_color command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_background_color" - ] - } - }, - "deny-set-badge-count": { - "identifier": "deny-set-badge-count", - "description": "Denies the set_badge_count command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_badge_count" - ] - } - }, - "deny-set-badge-label": { - "identifier": "deny-set-badge-label", - "description": "Denies the set_badge_label command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_badge_label" - ] - } - }, - "deny-set-closable": { - "identifier": "deny-set-closable", - "description": "Denies the set_closable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_closable" - ] - } - }, - "deny-set-content-protected": { - "identifier": "deny-set-content-protected", - "description": "Denies the set_content_protected command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_content_protected" - ] - } - }, - "deny-set-cursor-grab": { - "identifier": "deny-set-cursor-grab", - "description": "Denies the set_cursor_grab command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_cursor_grab" - ] - } - }, - "deny-set-cursor-icon": { - "identifier": "deny-set-cursor-icon", - "description": "Denies the set_cursor_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_cursor_icon" - ] - } - }, - "deny-set-cursor-position": { - "identifier": "deny-set-cursor-position", - "description": "Denies the set_cursor_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_cursor_position" - ] - } - }, - "deny-set-cursor-visible": { - "identifier": "deny-set-cursor-visible", - "description": "Denies the set_cursor_visible command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_cursor_visible" - ] - } - }, - "deny-set-decorations": { - "identifier": "deny-set-decorations", - "description": "Denies the set_decorations command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_decorations" - ] - } - }, - "deny-set-effects": { - "identifier": "deny-set-effects", - "description": "Denies the set_effects command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_effects" - ] - } - }, - "deny-set-enabled": { - "identifier": "deny-set-enabled", - "description": "Denies the set_enabled command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_enabled" - ] - } - }, - "deny-set-focus": { - "identifier": "deny-set-focus", - "description": "Denies the set_focus command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_focus" - ] - } - }, - "deny-set-focusable": { - "identifier": "deny-set-focusable", - "description": "Denies the set_focusable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_focusable" - ] - } - }, - "deny-set-fullscreen": { - "identifier": "deny-set-fullscreen", - "description": "Denies the set_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_fullscreen" - ] - } - }, - "deny-set-icon": { - "identifier": "deny-set-icon", - "description": "Denies the set_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_icon" - ] - } - }, - "deny-set-ignore-cursor-events": { - "identifier": "deny-set-ignore-cursor-events", - "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_ignore_cursor_events" - ] - } - }, - "deny-set-max-size": { - "identifier": "deny-set-max-size", - "description": "Denies the set_max_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_max_size" - ] - } - }, - "deny-set-maximizable": { - "identifier": "deny-set-maximizable", - "description": "Denies the set_maximizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_maximizable" - ] - } - }, - "deny-set-min-size": { - "identifier": "deny-set-min-size", - "description": "Denies the set_min_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_min_size" - ] - } - }, - "deny-set-minimizable": { - "identifier": "deny-set-minimizable", - "description": "Denies the set_minimizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_minimizable" - ] - } - }, - "deny-set-overlay-icon": { - "identifier": "deny-set-overlay-icon", - "description": "Denies the set_overlay_icon command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_overlay_icon" - ] - } - }, - "deny-set-position": { - "identifier": "deny-set-position", - "description": "Denies the set_position command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_position" - ] - } - }, - "deny-set-progress-bar": { - "identifier": "deny-set-progress-bar", - "description": "Denies the set_progress_bar command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_progress_bar" - ] - } - }, - "deny-set-resizable": { - "identifier": "deny-set-resizable", - "description": "Denies the set_resizable command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_resizable" - ] - } - }, - "deny-set-shadow": { - "identifier": "deny-set-shadow", - "description": "Denies the set_shadow command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_shadow" - ] - } - }, - "deny-set-simple-fullscreen": { - "identifier": "deny-set-simple-fullscreen", - "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_simple_fullscreen" - ] - } - }, - "deny-set-size": { - "identifier": "deny-set-size", - "description": "Denies the set_size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_size" - ] - } - }, - "deny-set-size-constraints": { - "identifier": "deny-set-size-constraints", - "description": "Denies the set_size_constraints command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_size_constraints" - ] - } - }, - "deny-set-skip-taskbar": { - "identifier": "deny-set-skip-taskbar", - "description": "Denies the set_skip_taskbar command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_skip_taskbar" - ] - } - }, - "deny-set-theme": { - "identifier": "deny-set-theme", - "description": "Denies the set_theme command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_theme" - ] - } - }, - "deny-set-title": { - "identifier": "deny-set-title", - "description": "Denies the set_title command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_title" - ] - } - }, - "deny-set-title-bar-style": { - "identifier": "deny-set-title-bar-style", - "description": "Denies the set_title_bar_style command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_title_bar_style" - ] - } - }, - "deny-set-visible-on-all-workspaces": { - "identifier": "deny-set-visible-on-all-workspaces", - "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "set_visible_on_all_workspaces" - ] - } - }, - "deny-show": { - "identifier": "deny-show", - "description": "Denies the show command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "show" - ] - } - }, - "deny-start-dragging": { - "identifier": "deny-start-dragging", - "description": "Denies the start_dragging command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "start_dragging" - ] - } - }, - "deny-start-resize-dragging": { - "identifier": "deny-start-resize-dragging", - "description": "Denies the start_resize_dragging command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "start_resize_dragging" - ] - } - }, - "deny-theme": { - "identifier": "deny-theme", - "description": "Denies the theme command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "theme" - ] - } - }, - "deny-title": { - "identifier": "deny-title", - "description": "Denies the title command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "title" - ] - } - }, - "deny-toggle-maximize": { - "identifier": "deny-toggle-maximize", - "description": "Denies the toggle_maximize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "toggle_maximize" - ] - } - }, - "deny-unmaximize": { - "identifier": "deny-unmaximize", - "description": "Denies the unmaximize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "unmaximize" - ] - } - }, - "deny-unminimize": { - "identifier": "deny-unminimize", - "description": "Denies the unminimize command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "unminimize" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "dialog": { - "default_permission": { - "identifier": "default", - "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n", - "permissions": [ - "allow-message", - "allow-save", - "allow-open" - ] - }, - "permissions": { - "allow-ask": { - "identifier": "allow-ask", - "description": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", - "commands": { - "allow": [ - "message" - ], - "deny": [] - } - }, - "allow-confirm": { - "identifier": "allow-confirm", - "description": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", - "commands": { - "allow": [ - "message" - ], - "deny": [] - } - }, - "allow-message": { - "identifier": "allow-message", - "description": "Enables the message command without any pre-configured scope.", - "commands": { - "allow": [ - "message" - ], - "deny": [] - } - }, - "allow-open": { - "identifier": "allow-open", - "description": "Enables the open command without any pre-configured scope.", - "commands": { - "allow": [ - "open" - ], - "deny": [] - } - }, - "allow-save": { - "identifier": "allow-save", - "description": "Enables the save command without any pre-configured scope.", - "commands": { - "allow": [ - "save" - ], - "deny": [] - } - }, - "deny-ask": { - "identifier": "deny-ask", - "description": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", - "commands": { - "allow": [], - "deny": [ - "message" - ] - } - }, - "deny-confirm": { - "identifier": "deny-confirm", - "description": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", - "commands": { - "allow": [], - "deny": [ - "message" - ] - } - }, - "deny-message": { - "identifier": "deny-message", - "description": "Denies the message command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "message" - ] - } - }, - "deny-open": { - "identifier": "deny-open", - "description": "Denies the open command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "open" - ] - } - }, - "deny-save": { - "identifier": "deny-save", - "description": "Denies the save command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "save" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "fs": { - "default_permission": { - "identifier": "default", - "description": "This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n", - "permissions": [ - "create-app-specific-dirs", - "read-app-specific-dirs-recursive", - "deny-default" - ] - }, - "permissions": { - "allow-copy-file": { - "identifier": "allow-copy-file", - "description": "Enables the copy_file command without any pre-configured scope.", - "commands": { - "allow": [ - "copy_file" - ], - "deny": [] - } - }, - "allow-create": { - "identifier": "allow-create", - "description": "Enables the create command without any pre-configured scope.", - "commands": { - "allow": [ - "create" - ], - "deny": [] - } - }, - "allow-exists": { - "identifier": "allow-exists", - "description": "Enables the exists command without any pre-configured scope.", - "commands": { - "allow": [ - "exists" - ], - "deny": [] - } - }, - "allow-fstat": { - "identifier": "allow-fstat", - "description": "Enables the fstat command without any pre-configured scope.", - "commands": { - "allow": [ - "fstat" - ], - "deny": [] - } - }, - "allow-ftruncate": { - "identifier": "allow-ftruncate", - "description": "Enables the ftruncate command without any pre-configured scope.", - "commands": { - "allow": [ - "ftruncate" - ], - "deny": [] - } - }, - "allow-lstat": { - "identifier": "allow-lstat", - "description": "Enables the lstat command without any pre-configured scope.", - "commands": { - "allow": [ - "lstat" - ], - "deny": [] - } - }, - "allow-mkdir": { - "identifier": "allow-mkdir", - "description": "Enables the mkdir command without any pre-configured scope.", - "commands": { - "allow": [ - "mkdir" - ], - "deny": [] - } - }, - "allow-open": { - "identifier": "allow-open", - "description": "Enables the open command without any pre-configured scope.", - "commands": { - "allow": [ - "open" - ], - "deny": [] - } - }, - "allow-read": { - "identifier": "allow-read", - "description": "Enables the read command without any pre-configured scope.", - "commands": { - "allow": [ - "read" - ], - "deny": [] - } - }, - "allow-read-dir": { - "identifier": "allow-read-dir", - "description": "Enables the read_dir command without any pre-configured scope.", - "commands": { - "allow": [ - "read_dir" - ], - "deny": [] - } - }, - "allow-read-file": { - "identifier": "allow-read-file", - "description": "Enables the read_file command without any pre-configured scope.", - "commands": { - "allow": [ - "read_file" - ], - "deny": [] - } - }, - "allow-read-text-file": { - "identifier": "allow-read-text-file", - "description": "Enables the read_text_file command without any pre-configured scope.", - "commands": { - "allow": [ - "read_text_file" - ], - "deny": [] - } - }, - "allow-read-text-file-lines": { - "identifier": "allow-read-text-file-lines", - "description": "Enables the read_text_file_lines command without any pre-configured scope.", - "commands": { - "allow": [ - "read_text_file_lines", - "read_text_file_lines_next" - ], - "deny": [] - } - }, - "allow-read-text-file-lines-next": { - "identifier": "allow-read-text-file-lines-next", - "description": "Enables the read_text_file_lines_next command without any pre-configured scope.", - "commands": { - "allow": [ - "read_text_file_lines_next" - ], - "deny": [] - } - }, - "allow-remove": { - "identifier": "allow-remove", - "description": "Enables the remove command without any pre-configured scope.", - "commands": { - "allow": [ - "remove" - ], - "deny": [] - } - }, - "allow-rename": { - "identifier": "allow-rename", - "description": "Enables the rename command without any pre-configured scope.", - "commands": { - "allow": [ - "rename" - ], - "deny": [] - } - }, - "allow-seek": { - "identifier": "allow-seek", - "description": "Enables the seek command without any pre-configured scope.", - "commands": { - "allow": [ - "seek" - ], - "deny": [] - } - }, - "allow-size": { - "identifier": "allow-size", - "description": "Enables the size command without any pre-configured scope.", - "commands": { - "allow": [ - "size" - ], - "deny": [] - } - }, - "allow-start-accessing-security-scoped-resource": { - "identifier": "allow-start-accessing-security-scoped-resource", - "description": "Enables the start_accessing_security_scoped_resource command without any pre-configured scope.", - "commands": { - "allow": [ - "start_accessing_security_scoped_resource" - ], - "deny": [] - } - }, - "allow-stat": { - "identifier": "allow-stat", - "description": "Enables the stat command without any pre-configured scope.", - "commands": { - "allow": [ - "stat" - ], - "deny": [] - } - }, - "allow-stop-accessing-security-scoped-resource": { - "identifier": "allow-stop-accessing-security-scoped-resource", - "description": "Enables the stop_accessing_security_scoped_resource command without any pre-configured scope.", - "commands": { - "allow": [ - "stop_accessing_security_scoped_resource" - ], - "deny": [] - } - }, - "allow-truncate": { - "identifier": "allow-truncate", - "description": "Enables the truncate command without any pre-configured scope.", - "commands": { - "allow": [ - "truncate" - ], - "deny": [] - } - }, - "allow-unwatch": { - "identifier": "allow-unwatch", - "description": "Enables the unwatch command without any pre-configured scope.", - "commands": { - "allow": [ - "unwatch" - ], - "deny": [] - } - }, - "allow-watch": { - "identifier": "allow-watch", - "description": "Enables the watch command without any pre-configured scope.", - "commands": { - "allow": [ - "watch" - ], - "deny": [] - } - }, - "allow-write": { - "identifier": "allow-write", - "description": "Enables the write command without any pre-configured scope.", - "commands": { - "allow": [ - "write" - ], - "deny": [] - } - }, - "allow-write-file": { - "identifier": "allow-write-file", - "description": "Enables the write_file command without any pre-configured scope.", - "commands": { - "allow": [ - "write_file", - "open", - "write" - ], - "deny": [] - } - }, - "allow-write-text-file": { - "identifier": "allow-write-text-file", - "description": "Enables the write_text_file command without any pre-configured scope.", - "commands": { - "allow": [ - "write_text_file" - ], - "deny": [] - } - }, - "create-app-specific-dirs": { - "identifier": "create-app-specific-dirs", - "description": "This permissions allows to create the application specific directories.\n", - "commands": { - "allow": [ - "mkdir", - "scope-app-index" - ], - "deny": [] - } - }, - "deny-copy-file": { - "identifier": "deny-copy-file", - "description": "Denies the copy_file command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "copy_file" - ] - } - }, - "deny-create": { - "identifier": "deny-create", - "description": "Denies the create command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "create" - ] - } - }, - "deny-exists": { - "identifier": "deny-exists", - "description": "Denies the exists command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "exists" - ] - } - }, - "deny-fstat": { - "identifier": "deny-fstat", - "description": "Denies the fstat command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "fstat" - ] - } - }, - "deny-ftruncate": { - "identifier": "deny-ftruncate", - "description": "Denies the ftruncate command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "ftruncate" - ] - } - }, - "deny-lstat": { - "identifier": "deny-lstat", - "description": "Denies the lstat command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "lstat" - ] - } - }, - "deny-mkdir": { - "identifier": "deny-mkdir", - "description": "Denies the mkdir command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "mkdir" - ] - } - }, - "deny-open": { - "identifier": "deny-open", - "description": "Denies the open command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "open" - ] - } - }, - "deny-read": { - "identifier": "deny-read", - "description": "Denies the read command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read" - ] - } - }, - "deny-read-dir": { - "identifier": "deny-read-dir", - "description": "Denies the read_dir command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read_dir" - ] - } - }, - "deny-read-file": { - "identifier": "deny-read-file", - "description": "Denies the read_file command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read_file" - ] - } - }, - "deny-read-text-file": { - "identifier": "deny-read-text-file", - "description": "Denies the read_text_file command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read_text_file" - ] - } - }, - "deny-read-text-file-lines": { - "identifier": "deny-read-text-file-lines", - "description": "Denies the read_text_file_lines command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read_text_file_lines" - ] - } - }, - "deny-read-text-file-lines-next": { - "identifier": "deny-read-text-file-lines-next", - "description": "Denies the read_text_file_lines_next command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "read_text_file_lines_next" - ] - } - }, - "deny-remove": { - "identifier": "deny-remove", - "description": "Denies the remove command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "remove" - ] - } - }, - "deny-rename": { - "identifier": "deny-rename", - "description": "Denies the rename command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "rename" - ] - } - }, - "deny-seek": { - "identifier": "deny-seek", - "description": "Denies the seek command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "seek" - ] - } - }, - "deny-size": { - "identifier": "deny-size", - "description": "Denies the size command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "size" - ] - } - }, - "deny-start-accessing-security-scoped-resource": { - "identifier": "deny-start-accessing-security-scoped-resource", - "description": "Denies the start_accessing_security_scoped_resource command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "start_accessing_security_scoped_resource" - ] - } - }, - "deny-stat": { - "identifier": "deny-stat", - "description": "Denies the stat command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "stat" - ] - } - }, - "deny-stop-accessing-security-scoped-resource": { - "identifier": "deny-stop-accessing-security-scoped-resource", - "description": "Denies the stop_accessing_security_scoped_resource command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "stop_accessing_security_scoped_resource" - ] - } - }, - "deny-truncate": { - "identifier": "deny-truncate", - "description": "Denies the truncate command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "truncate" - ] - } - }, - "deny-unwatch": { - "identifier": "deny-unwatch", - "description": "Denies the unwatch command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "unwatch" - ] - } - }, - "deny-watch": { - "identifier": "deny-watch", - "description": "Denies the watch command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "watch" - ] - } - }, - "deny-webview-data-linux": { - "identifier": "deny-webview-data-linux", - "description": "This denies read access to the\n`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.", - "commands": { - "allow": [], - "deny": [] - } - }, - "deny-webview-data-windows": { - "identifier": "deny-webview-data-windows", - "description": "This denies read access to the\n`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.", - "commands": { - "allow": [], - "deny": [] - } - }, - "deny-write": { - "identifier": "deny-write", - "description": "Denies the write command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "write" - ] - } - }, - "deny-write-file": { - "identifier": "deny-write-file", - "description": "Denies the write_file command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "write_file" - ] - } - }, - "deny-write-text-file": { - "identifier": "deny-write-text-file", - "description": "Denies the write_text_file command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "write_text_file" - ] - } - }, - "read-all": { - "identifier": "read-all", - "description": "This enables all read related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "read_dir", - "read_file", - "read", - "open", - "read_text_file", - "read_text_file_lines", - "read_text_file_lines_next", - "seek", - "stat", - "lstat", - "fstat", - "exists", - "watch", - "unwatch" - ], - "deny": [] - } - }, - "read-app-specific-dirs-recursive": { - "identifier": "read-app-specific-dirs-recursive", - "description": "This permission allows recursive read functionality on the application\nspecific base directories. \n", - "commands": { - "allow": [ - "read_dir", - "read_file", - "read_text_file", - "read_text_file_lines", - "read_text_file_lines_next", - "exists", - "scope-app-recursive" - ], - "deny": [] - } - }, - "read-dirs": { - "identifier": "read-dirs", - "description": "This enables directory read and file metadata related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "read_dir", - "stat", - "lstat", - "fstat", - "exists" - ], - "deny": [] - } - }, - "read-files": { - "identifier": "read-files", - "description": "This enables file read related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "read_file", - "read", - "open", - "read_text_file", - "read_text_file_lines", - "read_text_file_lines_next", - "seek", - "stat", - "lstat", - "fstat", - "exists" - ], - "deny": [] - } - }, - "read-meta": { - "identifier": "read-meta", - "description": "This enables all index or metadata related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "read_dir", - "stat", - "lstat", - "fstat", - "exists", - "size" - ], - "deny": [] - } - }, - "scope": { - "identifier": "scope", - "description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n", - "commands": { - "allow": [], - "deny": [] - } - }, - "scope-app": { - "identifier": "scope-app", - "description": "This scope permits access to all files and list content of top level directories in the application folders.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - }, - { - "path": "$APPCONFIG/*" - }, - { - "path": "$APPDATA" - }, - { - "path": "$APPDATA/*" - }, - { - "path": "$APPLOCALDATA" - }, - { - "path": "$APPLOCALDATA/*" - }, - { - "path": "$APPCACHE" - }, - { - "path": "$APPCACHE/*" - }, - { - "path": "$APPLOG" - }, - { - "path": "$APPLOG/*" - } - ] - } - }, - "scope-app-index": { - "identifier": "scope-app-index", - "description": "This scope permits to list all files and folders in the application directories.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - }, - { - "path": "$APPDATA" - }, - { - "path": "$APPLOCALDATA" - }, - { - "path": "$APPCACHE" - }, - { - "path": "$APPLOG" - } - ] - } - }, - "scope-app-recursive": { - "identifier": "scope-app-recursive", - "description": "This scope permits recursive access to the complete application folders, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - }, - { - "path": "$APPCONFIG/**" - }, - { - "path": "$APPDATA" - }, - { - "path": "$APPDATA/**" - }, - { - "path": "$APPLOCALDATA" - }, - { - "path": "$APPLOCALDATA/**" - }, - { - "path": "$APPCACHE" - }, - { - "path": "$APPCACHE/**" - }, - { - "path": "$APPLOG" - }, - { - "path": "$APPLOG/**" - } - ] - } - }, - "scope-appcache": { - "identifier": "scope-appcache", - "description": "This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCACHE" - }, - { - "path": "$APPCACHE/*" - } - ] - } - }, - "scope-appcache-index": { - "identifier": "scope-appcache-index", - "description": "This scope permits to list all files and folders in the `$APPCACHE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCACHE" - } - ] - } - }, - "scope-appcache-recursive": { - "identifier": "scope-appcache-recursive", - "description": "This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCACHE" - }, - { - "path": "$APPCACHE/**" - } - ] - } - }, - "scope-appconfig": { - "identifier": "scope-appconfig", - "description": "This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - }, - { - "path": "$APPCONFIG/*" - } - ] - } - }, - "scope-appconfig-index": { - "identifier": "scope-appconfig-index", - "description": "This scope permits to list all files and folders in the `$APPCONFIG`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - } - ] - } - }, - "scope-appconfig-recursive": { - "identifier": "scope-appconfig-recursive", - "description": "This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPCONFIG" - }, - { - "path": "$APPCONFIG/**" - } - ] - } - }, - "scope-appdata": { - "identifier": "scope-appdata", - "description": "This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPDATA" - }, - { - "path": "$APPDATA/*" - } - ] - } - }, - "scope-appdata-index": { - "identifier": "scope-appdata-index", - "description": "This scope permits to list all files and folders in the `$APPDATA`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPDATA" - } - ] - } - }, - "scope-appdata-recursive": { - "identifier": "scope-appdata-recursive", - "description": "This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPDATA" - }, - { - "path": "$APPDATA/**" - } - ] - } - }, - "scope-applocaldata": { - "identifier": "scope-applocaldata", - "description": "This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOCALDATA" - }, - { - "path": "$APPLOCALDATA/*" - } - ] - } - }, - "scope-applocaldata-index": { - "identifier": "scope-applocaldata-index", - "description": "This scope permits to list all files and folders in the `$APPLOCALDATA`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOCALDATA" - } - ] - } - }, - "scope-applocaldata-recursive": { - "identifier": "scope-applocaldata-recursive", - "description": "This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOCALDATA" - }, - { - "path": "$APPLOCALDATA/**" - } - ] - } - }, - "scope-applog": { - "identifier": "scope-applog", - "description": "This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOG" - }, - { - "path": "$APPLOG/*" - } - ] - } - }, - "scope-applog-index": { - "identifier": "scope-applog-index", - "description": "This scope permits to list all files and folders in the `$APPLOG`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOG" - } - ] - } - }, - "scope-applog-recursive": { - "identifier": "scope-applog-recursive", - "description": "This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$APPLOG" - }, - { - "path": "$APPLOG/**" - } - ] - } - }, - "scope-audio": { - "identifier": "scope-audio", - "description": "This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$AUDIO" - }, - { - "path": "$AUDIO/*" - } - ] - } - }, - "scope-audio-index": { - "identifier": "scope-audio-index", - "description": "This scope permits to list all files and folders in the `$AUDIO`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$AUDIO" - } - ] - } - }, - "scope-audio-recursive": { - "identifier": "scope-audio-recursive", - "description": "This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$AUDIO" - }, - { - "path": "$AUDIO/**" - } - ] - } - }, - "scope-cache": { - "identifier": "scope-cache", - "description": "This scope permits access to all files and list content of top level directories in the `$CACHE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CACHE" - }, - { - "path": "$CACHE/*" - } - ] - } - }, - "scope-cache-index": { - "identifier": "scope-cache-index", - "description": "This scope permits to list all files and folders in the `$CACHE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CACHE" - } - ] - } - }, - "scope-cache-recursive": { - "identifier": "scope-cache-recursive", - "description": "This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CACHE" - }, - { - "path": "$CACHE/**" - } - ] - } - }, - "scope-config": { - "identifier": "scope-config", - "description": "This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CONFIG" - }, - { - "path": "$CONFIG/*" - } - ] - } - }, - "scope-config-index": { - "identifier": "scope-config-index", - "description": "This scope permits to list all files and folders in the `$CONFIG`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CONFIG" - } - ] - } - }, - "scope-config-recursive": { - "identifier": "scope-config-recursive", - "description": "This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$CONFIG" - }, - { - "path": "$CONFIG/**" - } - ] - } - }, - "scope-data": { - "identifier": "scope-data", - "description": "This scope permits access to all files and list content of top level directories in the `$DATA` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DATA" - }, - { - "path": "$DATA/*" - } - ] - } - }, - "scope-data-index": { - "identifier": "scope-data-index", - "description": "This scope permits to list all files and folders in the `$DATA`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DATA" - } - ] - } - }, - "scope-data-recursive": { - "identifier": "scope-data-recursive", - "description": "This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DATA" - }, - { - "path": "$DATA/**" - } - ] - } - }, - "scope-desktop": { - "identifier": "scope-desktop", - "description": "This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DESKTOP" - }, - { - "path": "$DESKTOP/*" - } - ] - } - }, - "scope-desktop-index": { - "identifier": "scope-desktop-index", - "description": "This scope permits to list all files and folders in the `$DESKTOP`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DESKTOP" - } - ] - } - }, - "scope-desktop-recursive": { - "identifier": "scope-desktop-recursive", - "description": "This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DESKTOP" - }, - { - "path": "$DESKTOP/**" - } - ] - } - }, - "scope-document": { - "identifier": "scope-document", - "description": "This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOCUMENT" - }, - { - "path": "$DOCUMENT/*" - } - ] - } - }, - "scope-document-index": { - "identifier": "scope-document-index", - "description": "This scope permits to list all files and folders in the `$DOCUMENT`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOCUMENT" - } - ] - } - }, - "scope-document-recursive": { - "identifier": "scope-document-recursive", - "description": "This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOCUMENT" - }, - { - "path": "$DOCUMENT/**" - } - ] - } - }, - "scope-download": { - "identifier": "scope-download", - "description": "This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOWNLOAD" - }, - { - "path": "$DOWNLOAD/*" - } - ] - } - }, - "scope-download-index": { - "identifier": "scope-download-index", - "description": "This scope permits to list all files and folders in the `$DOWNLOAD`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOWNLOAD" - } - ] - } - }, - "scope-download-recursive": { - "identifier": "scope-download-recursive", - "description": "This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$DOWNLOAD" - }, - { - "path": "$DOWNLOAD/**" - } - ] - } - }, - "scope-exe": { - "identifier": "scope-exe", - "description": "This scope permits access to all files and list content of top level directories in the `$EXE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$EXE" - }, - { - "path": "$EXE/*" - } - ] - } - }, - "scope-exe-index": { - "identifier": "scope-exe-index", - "description": "This scope permits to list all files and folders in the `$EXE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$EXE" - } - ] - } - }, - "scope-exe-recursive": { - "identifier": "scope-exe-recursive", - "description": "This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$EXE" - }, - { - "path": "$EXE/**" - } - ] - } - }, - "scope-font": { - "identifier": "scope-font", - "description": "This scope permits access to all files and list content of top level directories in the `$FONT` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$FONT" - }, - { - "path": "$FONT/*" - } - ] - } - }, - "scope-font-index": { - "identifier": "scope-font-index", - "description": "This scope permits to list all files and folders in the `$FONT`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$FONT" - } - ] - } - }, - "scope-font-recursive": { - "identifier": "scope-font-recursive", - "description": "This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$FONT" - }, - { - "path": "$FONT/**" - } - ] - } - }, - "scope-home": { - "identifier": "scope-home", - "description": "This scope permits access to all files and list content of top level directories in the `$HOME` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$HOME" - }, - { - "path": "$HOME/*" - } - ] - } - }, - "scope-home-index": { - "identifier": "scope-home-index", - "description": "This scope permits to list all files and folders in the `$HOME`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$HOME" - } - ] - } - }, - "scope-home-recursive": { - "identifier": "scope-home-recursive", - "description": "This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$HOME" - }, - { - "path": "$HOME/**" - } - ] - } - }, - "scope-localdata": { - "identifier": "scope-localdata", - "description": "This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOCALDATA" - }, - { - "path": "$LOCALDATA/*" - } - ] - } - }, - "scope-localdata-index": { - "identifier": "scope-localdata-index", - "description": "This scope permits to list all files and folders in the `$LOCALDATA`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOCALDATA" - } - ] - } - }, - "scope-localdata-recursive": { - "identifier": "scope-localdata-recursive", - "description": "This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOCALDATA" - }, - { - "path": "$LOCALDATA/**" - } - ] - } - }, - "scope-log": { - "identifier": "scope-log", - "description": "This scope permits access to all files and list content of top level directories in the `$LOG` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOG" - }, - { - "path": "$LOG/*" - } - ] - } - }, - "scope-log-index": { - "identifier": "scope-log-index", - "description": "This scope permits to list all files and folders in the `$LOG`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOG" - } - ] - } - }, - "scope-log-recursive": { - "identifier": "scope-log-recursive", - "description": "This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$LOG" - }, - { - "path": "$LOG/**" - } - ] - } - }, - "scope-picture": { - "identifier": "scope-picture", - "description": "This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PICTURE" - }, - { - "path": "$PICTURE/*" - } - ] - } - }, - "scope-picture-index": { - "identifier": "scope-picture-index", - "description": "This scope permits to list all files and folders in the `$PICTURE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PICTURE" - } - ] - } - }, - "scope-picture-recursive": { - "identifier": "scope-picture-recursive", - "description": "This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PICTURE" - }, - { - "path": "$PICTURE/**" - } - ] - } - }, - "scope-public": { - "identifier": "scope-public", - "description": "This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PUBLIC" - }, - { - "path": "$PUBLIC/*" - } - ] - } - }, - "scope-public-index": { - "identifier": "scope-public-index", - "description": "This scope permits to list all files and folders in the `$PUBLIC`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PUBLIC" - } - ] - } - }, - "scope-public-recursive": { - "identifier": "scope-public-recursive", - "description": "This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$PUBLIC" - }, - { - "path": "$PUBLIC/**" - } - ] - } - }, - "scope-resource": { - "identifier": "scope-resource", - "description": "This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RESOURCE" - }, - { - "path": "$RESOURCE/*" - } - ] - } - }, - "scope-resource-index": { - "identifier": "scope-resource-index", - "description": "This scope permits to list all files and folders in the `$RESOURCE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RESOURCE" - } - ] - } - }, - "scope-resource-recursive": { - "identifier": "scope-resource-recursive", - "description": "This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RESOURCE" - }, - { - "path": "$RESOURCE/**" - } - ] - } - }, - "scope-runtime": { - "identifier": "scope-runtime", - "description": "This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RUNTIME" - }, - { - "path": "$RUNTIME/*" - } - ] - } - }, - "scope-runtime-index": { - "identifier": "scope-runtime-index", - "description": "This scope permits to list all files and folders in the `$RUNTIME`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RUNTIME" - } - ] - } - }, - "scope-runtime-recursive": { - "identifier": "scope-runtime-recursive", - "description": "This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$RUNTIME" - }, - { - "path": "$RUNTIME/**" - } - ] - } - }, - "scope-temp": { - "identifier": "scope-temp", - "description": "This scope permits access to all files and list content of top level directories in the `$TEMP` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMP" - }, - { - "path": "$TEMP/*" - } - ] - } - }, - "scope-temp-index": { - "identifier": "scope-temp-index", - "description": "This scope permits to list all files and folders in the `$TEMP`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMP" - } - ] - } - }, - "scope-temp-recursive": { - "identifier": "scope-temp-recursive", - "description": "This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMP" - }, - { - "path": "$TEMP/**" - } - ] - } - }, - "scope-template": { - "identifier": "scope-template", - "description": "This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMPLATE" - }, - { - "path": "$TEMPLATE/*" - } - ] - } - }, - "scope-template-index": { - "identifier": "scope-template-index", - "description": "This scope permits to list all files and folders in the `$TEMPLATE`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMPLATE" - } - ] - } - }, - "scope-template-recursive": { - "identifier": "scope-template-recursive", - "description": "This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$TEMPLATE" - }, - { - "path": "$TEMPLATE/**" - } - ] - } - }, - "scope-video": { - "identifier": "scope-video", - "description": "This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$VIDEO" - }, - { - "path": "$VIDEO/*" - } - ] - } - }, - "scope-video-index": { - "identifier": "scope-video-index", - "description": "This scope permits to list all files and folders in the `$VIDEO`folder.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$VIDEO" - } - ] - } - }, - "scope-video-recursive": { - "identifier": "scope-video-recursive", - "description": "This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.", - "commands": { - "allow": [], - "deny": [] - }, - "scope": { - "allow": [ - { - "path": "$VIDEO" - }, - { - "path": "$VIDEO/**" - } - ] - } - }, - "write-all": { - "identifier": "write-all", - "description": "This enables all write related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "mkdir", - "create", - "copy_file", - "remove", - "rename", - "truncate", - "ftruncate", - "write", - "write_file", - "write_text_file" - ], - "deny": [] - } - }, - "write-files": { - "identifier": "write-files", - "description": "This enables all file write related commands without any pre-configured accessible paths.", - "commands": { - "allow": [ - "create", - "copy_file", - "remove", - "rename", - "truncate", - "ftruncate", - "write", - "write_file", - "write_text_file" - ], - "deny": [] - } - } - }, - "permission_sets": { - "allow-app-meta": { - "identifier": "allow-app-meta", - "description": "This allows non-recursive read access to metadata of the application folders, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-app-index" - ] - }, - "allow-app-meta-recursive": { - "identifier": "allow-app-meta-recursive", - "description": "This allows full recursive read access to metadata of the application folders, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-app-recursive" - ] - }, - "allow-app-read": { - "identifier": "allow-app-read", - "description": "This allows non-recursive read access to the application folders.", - "permissions": [ - "read-all", - "scope-app" - ] - }, - "allow-app-read-recursive": { - "identifier": "allow-app-read-recursive", - "description": "This allows full recursive read access to the complete application folders, files and subdirectories.", - "permissions": [ - "read-all", - "scope-app-recursive" - ] - }, - "allow-app-write": { - "identifier": "allow-app-write", - "description": "This allows non-recursive write access to the application folders.", - "permissions": [ - "write-all", - "scope-app" - ] - }, - "allow-app-write-recursive": { - "identifier": "allow-app-write-recursive", - "description": "This allows full recursive write access to the complete application folders, files and subdirectories.", - "permissions": [ - "write-all", - "scope-app-recursive" - ] - }, - "allow-appcache-meta": { - "identifier": "allow-appcache-meta", - "description": "This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appcache-index" - ] - }, - "allow-appcache-meta-recursive": { - "identifier": "allow-appcache-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appcache-recursive" - ] - }, - "allow-appcache-read": { - "identifier": "allow-appcache-read", - "description": "This allows non-recursive read access to the `$APPCACHE` folder.", - "permissions": [ - "read-all", - "scope-appcache" - ] - }, - "allow-appcache-read-recursive": { - "identifier": "allow-appcache-read-recursive", - "description": "This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-appcache-recursive" - ] - }, - "allow-appcache-write": { - "identifier": "allow-appcache-write", - "description": "This allows non-recursive write access to the `$APPCACHE` folder.", - "permissions": [ - "write-all", - "scope-appcache" - ] - }, - "allow-appcache-write-recursive": { - "identifier": "allow-appcache-write-recursive", - "description": "This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-appcache-recursive" - ] - }, - "allow-appconfig-meta": { - "identifier": "allow-appconfig-meta", - "description": "This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appconfig-index" - ] - }, - "allow-appconfig-meta-recursive": { - "identifier": "allow-appconfig-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appconfig-recursive" - ] - }, - "allow-appconfig-read": { - "identifier": "allow-appconfig-read", - "description": "This allows non-recursive read access to the `$APPCONFIG` folder.", - "permissions": [ - "read-all", - "scope-appconfig" - ] - }, - "allow-appconfig-read-recursive": { - "identifier": "allow-appconfig-read-recursive", - "description": "This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-appconfig-recursive" - ] - }, - "allow-appconfig-write": { - "identifier": "allow-appconfig-write", - "description": "This allows non-recursive write access to the `$APPCONFIG` folder.", - "permissions": [ - "write-all", - "scope-appconfig" - ] - }, - "allow-appconfig-write-recursive": { - "identifier": "allow-appconfig-write-recursive", - "description": "This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-appconfig-recursive" - ] - }, - "allow-appdata-meta": { - "identifier": "allow-appdata-meta", - "description": "This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appdata-index" - ] - }, - "allow-appdata-meta-recursive": { - "identifier": "allow-appdata-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-appdata-recursive" - ] - }, - "allow-appdata-read": { - "identifier": "allow-appdata-read", - "description": "This allows non-recursive read access to the `$APPDATA` folder.", - "permissions": [ - "read-all", - "scope-appdata" - ] - }, - "allow-appdata-read-recursive": { - "identifier": "allow-appdata-read-recursive", - "description": "This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-appdata-recursive" - ] - }, - "allow-appdata-write": { - "identifier": "allow-appdata-write", - "description": "This allows non-recursive write access to the `$APPDATA` folder.", - "permissions": [ - "write-all", - "scope-appdata" - ] - }, - "allow-appdata-write-recursive": { - "identifier": "allow-appdata-write-recursive", - "description": "This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-appdata-recursive" - ] - }, - "allow-applocaldata-meta": { - "identifier": "allow-applocaldata-meta", - "description": "This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-applocaldata-index" - ] - }, - "allow-applocaldata-meta-recursive": { - "identifier": "allow-applocaldata-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-applocaldata-recursive" - ] - }, - "allow-applocaldata-read": { - "identifier": "allow-applocaldata-read", - "description": "This allows non-recursive read access to the `$APPLOCALDATA` folder.", - "permissions": [ - "read-all", - "scope-applocaldata" - ] - }, - "allow-applocaldata-read-recursive": { - "identifier": "allow-applocaldata-read-recursive", - "description": "This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-applocaldata-recursive" - ] - }, - "allow-applocaldata-write": { - "identifier": "allow-applocaldata-write", - "description": "This allows non-recursive write access to the `$APPLOCALDATA` folder.", - "permissions": [ - "write-all", - "scope-applocaldata" - ] - }, - "allow-applocaldata-write-recursive": { - "identifier": "allow-applocaldata-write-recursive", - "description": "This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-applocaldata-recursive" - ] - }, - "allow-applog-meta": { - "identifier": "allow-applog-meta", - "description": "This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-applog-index" - ] - }, - "allow-applog-meta-recursive": { - "identifier": "allow-applog-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-applog-recursive" - ] - }, - "allow-applog-read": { - "identifier": "allow-applog-read", - "description": "This allows non-recursive read access to the `$APPLOG` folder.", - "permissions": [ - "read-all", - "scope-applog" - ] - }, - "allow-applog-read-recursive": { - "identifier": "allow-applog-read-recursive", - "description": "This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-applog-recursive" - ] - }, - "allow-applog-write": { - "identifier": "allow-applog-write", - "description": "This allows non-recursive write access to the `$APPLOG` folder.", - "permissions": [ - "write-all", - "scope-applog" - ] - }, - "allow-applog-write-recursive": { - "identifier": "allow-applog-write-recursive", - "description": "This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-applog-recursive" - ] - }, - "allow-audio-meta": { - "identifier": "allow-audio-meta", - "description": "This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-audio-index" - ] - }, - "allow-audio-meta-recursive": { - "identifier": "allow-audio-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-audio-recursive" - ] - }, - "allow-audio-read": { - "identifier": "allow-audio-read", - "description": "This allows non-recursive read access to the `$AUDIO` folder.", - "permissions": [ - "read-all", - "scope-audio" - ] - }, - "allow-audio-read-recursive": { - "identifier": "allow-audio-read-recursive", - "description": "This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-audio-recursive" - ] - }, - "allow-audio-write": { - "identifier": "allow-audio-write", - "description": "This allows non-recursive write access to the `$AUDIO` folder.", - "permissions": [ - "write-all", - "scope-audio" - ] - }, - "allow-audio-write-recursive": { - "identifier": "allow-audio-write-recursive", - "description": "This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-audio-recursive" - ] - }, - "allow-cache-meta": { - "identifier": "allow-cache-meta", - "description": "This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-cache-index" - ] - }, - "allow-cache-meta-recursive": { - "identifier": "allow-cache-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-cache-recursive" - ] - }, - "allow-cache-read": { - "identifier": "allow-cache-read", - "description": "This allows non-recursive read access to the `$CACHE` folder.", - "permissions": [ - "read-all", - "scope-cache" - ] - }, - "allow-cache-read-recursive": { - "identifier": "allow-cache-read-recursive", - "description": "This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-cache-recursive" - ] - }, - "allow-cache-write": { - "identifier": "allow-cache-write", - "description": "This allows non-recursive write access to the `$CACHE` folder.", - "permissions": [ - "write-all", - "scope-cache" - ] - }, - "allow-cache-write-recursive": { - "identifier": "allow-cache-write-recursive", - "description": "This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-cache-recursive" - ] - }, - "allow-config-meta": { - "identifier": "allow-config-meta", - "description": "This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-config-index" - ] - }, - "allow-config-meta-recursive": { - "identifier": "allow-config-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-config-recursive" - ] - }, - "allow-config-read": { - "identifier": "allow-config-read", - "description": "This allows non-recursive read access to the `$CONFIG` folder.", - "permissions": [ - "read-all", - "scope-config" - ] - }, - "allow-config-read-recursive": { - "identifier": "allow-config-read-recursive", - "description": "This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-config-recursive" - ] - }, - "allow-config-write": { - "identifier": "allow-config-write", - "description": "This allows non-recursive write access to the `$CONFIG` folder.", - "permissions": [ - "write-all", - "scope-config" - ] - }, - "allow-config-write-recursive": { - "identifier": "allow-config-write-recursive", - "description": "This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-config-recursive" - ] - }, - "allow-data-meta": { - "identifier": "allow-data-meta", - "description": "This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-data-index" - ] - }, - "allow-data-meta-recursive": { - "identifier": "allow-data-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-data-recursive" - ] - }, - "allow-data-read": { - "identifier": "allow-data-read", - "description": "This allows non-recursive read access to the `$DATA` folder.", - "permissions": [ - "read-all", - "scope-data" - ] - }, - "allow-data-read-recursive": { - "identifier": "allow-data-read-recursive", - "description": "This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-data-recursive" - ] - }, - "allow-data-write": { - "identifier": "allow-data-write", - "description": "This allows non-recursive write access to the `$DATA` folder.", - "permissions": [ - "write-all", - "scope-data" - ] - }, - "allow-data-write-recursive": { - "identifier": "allow-data-write-recursive", - "description": "This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-data-recursive" - ] - }, - "allow-desktop-meta": { - "identifier": "allow-desktop-meta", - "description": "This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-desktop-index" - ] - }, - "allow-desktop-meta-recursive": { - "identifier": "allow-desktop-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-desktop-recursive" - ] - }, - "allow-desktop-read": { - "identifier": "allow-desktop-read", - "description": "This allows non-recursive read access to the `$DESKTOP` folder.", - "permissions": [ - "read-all", - "scope-desktop" - ] - }, - "allow-desktop-read-recursive": { - "identifier": "allow-desktop-read-recursive", - "description": "This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-desktop-recursive" - ] - }, - "allow-desktop-write": { - "identifier": "allow-desktop-write", - "description": "This allows non-recursive write access to the `$DESKTOP` folder.", - "permissions": [ - "write-all", - "scope-desktop" - ] - }, - "allow-desktop-write-recursive": { - "identifier": "allow-desktop-write-recursive", - "description": "This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-desktop-recursive" - ] - }, - "allow-document-meta": { - "identifier": "allow-document-meta", - "description": "This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-document-index" - ] - }, - "allow-document-meta-recursive": { - "identifier": "allow-document-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-document-recursive" - ] - }, - "allow-document-read": { - "identifier": "allow-document-read", - "description": "This allows non-recursive read access to the `$DOCUMENT` folder.", - "permissions": [ - "read-all", - "scope-document" - ] - }, - "allow-document-read-recursive": { - "identifier": "allow-document-read-recursive", - "description": "This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-document-recursive" - ] - }, - "allow-document-write": { - "identifier": "allow-document-write", - "description": "This allows non-recursive write access to the `$DOCUMENT` folder.", - "permissions": [ - "write-all", - "scope-document" - ] - }, - "allow-document-write-recursive": { - "identifier": "allow-document-write-recursive", - "description": "This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-document-recursive" - ] - }, - "allow-download-meta": { - "identifier": "allow-download-meta", - "description": "This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-download-index" - ] - }, - "allow-download-meta-recursive": { - "identifier": "allow-download-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-download-recursive" - ] - }, - "allow-download-read": { - "identifier": "allow-download-read", - "description": "This allows non-recursive read access to the `$DOWNLOAD` folder.", - "permissions": [ - "read-all", - "scope-download" - ] - }, - "allow-download-read-recursive": { - "identifier": "allow-download-read-recursive", - "description": "This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-download-recursive" - ] - }, - "allow-download-write": { - "identifier": "allow-download-write", - "description": "This allows non-recursive write access to the `$DOWNLOAD` folder.", - "permissions": [ - "write-all", - "scope-download" - ] - }, - "allow-download-write-recursive": { - "identifier": "allow-download-write-recursive", - "description": "This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-download-recursive" - ] - }, - "allow-exe-meta": { - "identifier": "allow-exe-meta", - "description": "This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-exe-index" - ] - }, - "allow-exe-meta-recursive": { - "identifier": "allow-exe-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-exe-recursive" - ] - }, - "allow-exe-read": { - "identifier": "allow-exe-read", - "description": "This allows non-recursive read access to the `$EXE` folder.", - "permissions": [ - "read-all", - "scope-exe" - ] - }, - "allow-exe-read-recursive": { - "identifier": "allow-exe-read-recursive", - "description": "This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-exe-recursive" - ] - }, - "allow-exe-write": { - "identifier": "allow-exe-write", - "description": "This allows non-recursive write access to the `$EXE` folder.", - "permissions": [ - "write-all", - "scope-exe" - ] - }, - "allow-exe-write-recursive": { - "identifier": "allow-exe-write-recursive", - "description": "This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-exe-recursive" - ] - }, - "allow-font-meta": { - "identifier": "allow-font-meta", - "description": "This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-font-index" - ] - }, - "allow-font-meta-recursive": { - "identifier": "allow-font-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-font-recursive" - ] - }, - "allow-font-read": { - "identifier": "allow-font-read", - "description": "This allows non-recursive read access to the `$FONT` folder.", - "permissions": [ - "read-all", - "scope-font" - ] - }, - "allow-font-read-recursive": { - "identifier": "allow-font-read-recursive", - "description": "This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-font-recursive" - ] - }, - "allow-font-write": { - "identifier": "allow-font-write", - "description": "This allows non-recursive write access to the `$FONT` folder.", - "permissions": [ - "write-all", - "scope-font" - ] - }, - "allow-font-write-recursive": { - "identifier": "allow-font-write-recursive", - "description": "This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-font-recursive" - ] - }, - "allow-home-meta": { - "identifier": "allow-home-meta", - "description": "This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-home-index" - ] - }, - "allow-home-meta-recursive": { - "identifier": "allow-home-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-home-recursive" - ] - }, - "allow-home-read": { - "identifier": "allow-home-read", - "description": "This allows non-recursive read access to the `$HOME` folder.", - "permissions": [ - "read-all", - "scope-home" - ] - }, - "allow-home-read-recursive": { - "identifier": "allow-home-read-recursive", - "description": "This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-home-recursive" - ] - }, - "allow-home-write": { - "identifier": "allow-home-write", - "description": "This allows non-recursive write access to the `$HOME` folder.", - "permissions": [ - "write-all", - "scope-home" - ] - }, - "allow-home-write-recursive": { - "identifier": "allow-home-write-recursive", - "description": "This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-home-recursive" - ] - }, - "allow-localdata-meta": { - "identifier": "allow-localdata-meta", - "description": "This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-localdata-index" - ] - }, - "allow-localdata-meta-recursive": { - "identifier": "allow-localdata-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-localdata-recursive" - ] - }, - "allow-localdata-read": { - "identifier": "allow-localdata-read", - "description": "This allows non-recursive read access to the `$LOCALDATA` folder.", - "permissions": [ - "read-all", - "scope-localdata" - ] - }, - "allow-localdata-read-recursive": { - "identifier": "allow-localdata-read-recursive", - "description": "This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-localdata-recursive" - ] - }, - "allow-localdata-write": { - "identifier": "allow-localdata-write", - "description": "This allows non-recursive write access to the `$LOCALDATA` folder.", - "permissions": [ - "write-all", - "scope-localdata" - ] - }, - "allow-localdata-write-recursive": { - "identifier": "allow-localdata-write-recursive", - "description": "This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-localdata-recursive" - ] - }, - "allow-log-meta": { - "identifier": "allow-log-meta", - "description": "This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-log-index" - ] - }, - "allow-log-meta-recursive": { - "identifier": "allow-log-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-log-recursive" - ] - }, - "allow-log-read": { - "identifier": "allow-log-read", - "description": "This allows non-recursive read access to the `$LOG` folder.", - "permissions": [ - "read-all", - "scope-log" - ] - }, - "allow-log-read-recursive": { - "identifier": "allow-log-read-recursive", - "description": "This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-log-recursive" - ] - }, - "allow-log-write": { - "identifier": "allow-log-write", - "description": "This allows non-recursive write access to the `$LOG` folder.", - "permissions": [ - "write-all", - "scope-log" - ] - }, - "allow-log-write-recursive": { - "identifier": "allow-log-write-recursive", - "description": "This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-log-recursive" - ] - }, - "allow-picture-meta": { - "identifier": "allow-picture-meta", - "description": "This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-picture-index" - ] - }, - "allow-picture-meta-recursive": { - "identifier": "allow-picture-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-picture-recursive" - ] - }, - "allow-picture-read": { - "identifier": "allow-picture-read", - "description": "This allows non-recursive read access to the `$PICTURE` folder.", - "permissions": [ - "read-all", - "scope-picture" - ] - }, - "allow-picture-read-recursive": { - "identifier": "allow-picture-read-recursive", - "description": "This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-picture-recursive" - ] - }, - "allow-picture-write": { - "identifier": "allow-picture-write", - "description": "This allows non-recursive write access to the `$PICTURE` folder.", - "permissions": [ - "write-all", - "scope-picture" - ] - }, - "allow-picture-write-recursive": { - "identifier": "allow-picture-write-recursive", - "description": "This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-picture-recursive" - ] - }, - "allow-public-meta": { - "identifier": "allow-public-meta", - "description": "This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-public-index" - ] - }, - "allow-public-meta-recursive": { - "identifier": "allow-public-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-public-recursive" - ] - }, - "allow-public-read": { - "identifier": "allow-public-read", - "description": "This allows non-recursive read access to the `$PUBLIC` folder.", - "permissions": [ - "read-all", - "scope-public" - ] - }, - "allow-public-read-recursive": { - "identifier": "allow-public-read-recursive", - "description": "This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-public-recursive" - ] - }, - "allow-public-write": { - "identifier": "allow-public-write", - "description": "This allows non-recursive write access to the `$PUBLIC` folder.", - "permissions": [ - "write-all", - "scope-public" - ] - }, - "allow-public-write-recursive": { - "identifier": "allow-public-write-recursive", - "description": "This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-public-recursive" - ] - }, - "allow-resource-meta": { - "identifier": "allow-resource-meta", - "description": "This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-resource-index" - ] - }, - "allow-resource-meta-recursive": { - "identifier": "allow-resource-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-resource-recursive" - ] - }, - "allow-resource-read": { - "identifier": "allow-resource-read", - "description": "This allows non-recursive read access to the `$RESOURCE` folder.", - "permissions": [ - "read-all", - "scope-resource" - ] - }, - "allow-resource-read-recursive": { - "identifier": "allow-resource-read-recursive", - "description": "This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-resource-recursive" - ] - }, - "allow-resource-write": { - "identifier": "allow-resource-write", - "description": "This allows non-recursive write access to the `$RESOURCE` folder.", - "permissions": [ - "write-all", - "scope-resource" - ] - }, - "allow-resource-write-recursive": { - "identifier": "allow-resource-write-recursive", - "description": "This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-resource-recursive" - ] - }, - "allow-runtime-meta": { - "identifier": "allow-runtime-meta", - "description": "This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-runtime-index" - ] - }, - "allow-runtime-meta-recursive": { - "identifier": "allow-runtime-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-runtime-recursive" - ] - }, - "allow-runtime-read": { - "identifier": "allow-runtime-read", - "description": "This allows non-recursive read access to the `$RUNTIME` folder.", - "permissions": [ - "read-all", - "scope-runtime" - ] - }, - "allow-runtime-read-recursive": { - "identifier": "allow-runtime-read-recursive", - "description": "This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-runtime-recursive" - ] - }, - "allow-runtime-write": { - "identifier": "allow-runtime-write", - "description": "This allows non-recursive write access to the `$RUNTIME` folder.", - "permissions": [ - "write-all", - "scope-runtime" - ] - }, - "allow-runtime-write-recursive": { - "identifier": "allow-runtime-write-recursive", - "description": "This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-runtime-recursive" - ] - }, - "allow-temp-meta": { - "identifier": "allow-temp-meta", - "description": "This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-temp-index" - ] - }, - "allow-temp-meta-recursive": { - "identifier": "allow-temp-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-temp-recursive" - ] - }, - "allow-temp-read": { - "identifier": "allow-temp-read", - "description": "This allows non-recursive read access to the `$TEMP` folder.", - "permissions": [ - "read-all", - "scope-temp" - ] - }, - "allow-temp-read-recursive": { - "identifier": "allow-temp-read-recursive", - "description": "This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-temp-recursive" - ] - }, - "allow-temp-write": { - "identifier": "allow-temp-write", - "description": "This allows non-recursive write access to the `$TEMP` folder.", - "permissions": [ - "write-all", - "scope-temp" - ] - }, - "allow-temp-write-recursive": { - "identifier": "allow-temp-write-recursive", - "description": "This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-temp-recursive" - ] - }, - "allow-template-meta": { - "identifier": "allow-template-meta", - "description": "This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-template-index" - ] - }, - "allow-template-meta-recursive": { - "identifier": "allow-template-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-template-recursive" - ] - }, - "allow-template-read": { - "identifier": "allow-template-read", - "description": "This allows non-recursive read access to the `$TEMPLATE` folder.", - "permissions": [ - "read-all", - "scope-template" - ] - }, - "allow-template-read-recursive": { - "identifier": "allow-template-read-recursive", - "description": "This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-template-recursive" - ] - }, - "allow-template-write": { - "identifier": "allow-template-write", - "description": "This allows non-recursive write access to the `$TEMPLATE` folder.", - "permissions": [ - "write-all", - "scope-template" - ] - }, - "allow-template-write-recursive": { - "identifier": "allow-template-write-recursive", - "description": "This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-template-recursive" - ] - }, - "allow-video-meta": { - "identifier": "allow-video-meta", - "description": "This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-video-index" - ] - }, - "allow-video-meta-recursive": { - "identifier": "allow-video-meta-recursive", - "description": "This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.", - "permissions": [ - "read-meta", - "scope-video-recursive" - ] - }, - "allow-video-read": { - "identifier": "allow-video-read", - "description": "This allows non-recursive read access to the `$VIDEO` folder.", - "permissions": [ - "read-all", - "scope-video" - ] - }, - "allow-video-read-recursive": { - "identifier": "allow-video-read-recursive", - "description": "This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.", - "permissions": [ - "read-all", - "scope-video-recursive" - ] - }, - "allow-video-write": { - "identifier": "allow-video-write", - "description": "This allows non-recursive write access to the `$VIDEO` folder.", - "permissions": [ - "write-all", - "scope-video" - ] - }, - "allow-video-write-recursive": { - "identifier": "allow-video-write-recursive", - "description": "This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.", - "permissions": [ - "write-all", - "scope-video-recursive" - ] - }, - "deny-default": { - "identifier": "deny-default", - "description": "This denies access to dangerous Tauri relevant files and folders by default.", - "permissions": [ - "deny-webview-data-linux", - "deny-webview-data-windows" - ] - } - }, - "global_scope_schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "anyOf": [ - { - "description": "A path that can be accessed by the webview when using the fs APIs. FS scope path pattern.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - }, - { - "properties": { - "path": { - "description": "A path that can be accessed by the webview when using the fs APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - }, - "required": [ - "path" - ], - "type": "object" - } - ], - "description": "FS scope entry.", - "title": "FsScopeEntry" - } - }, - "log": { - "default_permission": { - "identifier": "default", - "description": "Allows the log command", - "permissions": [ - "allow-log" - ] - }, - "permissions": { - "allow-log": { - "identifier": "allow-log", - "description": "Enables the log command without any pre-configured scope.", - "commands": { - "allow": [ - "log" - ], - "deny": [] - } - }, - "deny-log": { - "identifier": "deny-log", - "description": "Denies the log command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "log" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - }, - "shell": { - "default_permission": { - "identifier": "default", - "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", - "permissions": [ - "allow-open" - ] - }, - "permissions": { - "allow-execute": { - "identifier": "allow-execute", - "description": "Enables the execute command without any pre-configured scope.", - "commands": { - "allow": [ - "execute" - ], - "deny": [] - } - }, - "allow-kill": { - "identifier": "allow-kill", - "description": "Enables the kill command without any pre-configured scope.", - "commands": { - "allow": [ - "kill" - ], - "deny": [] - } - }, - "allow-open": { - "identifier": "allow-open", - "description": "Enables the open command without any pre-configured scope.", - "commands": { - "allow": [ - "open" - ], - "deny": [] - } - }, - "allow-spawn": { - "identifier": "allow-spawn", - "description": "Enables the spawn command without any pre-configured scope.", - "commands": { - "allow": [ - "spawn" - ], - "deny": [] - } - }, - "allow-stdin-write": { - "identifier": "allow-stdin-write", - "description": "Enables the stdin_write command without any pre-configured scope.", - "commands": { - "allow": [ - "stdin_write" - ], - "deny": [] - } - }, - "deny-execute": { - "identifier": "deny-execute", - "description": "Denies the execute command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "execute" - ] - } - }, - "deny-kill": { - "identifier": "deny-kill", - "description": "Denies the kill command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "kill" - ] - } - }, - "deny-open": { - "identifier": "deny-open", - "description": "Denies the open command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "open" - ] - } - }, - "deny-spawn": { - "identifier": "deny-spawn", - "description": "Denies the spawn command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "spawn" - ] - } - }, - "deny-stdin-write": { - "identifier": "deny-stdin-write", - "description": "Denies the stdin_write command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "stdin_write" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "args": { - "allOf": [ - { - "$ref": "#/definitions/ShellScopeEntryAllowedArgs" - } - ], - "description": "The allowed arguments for the command execution." - }, - "cmd": { - "description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - }, - "name": { - "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", - "type": "string" - } - }, - "required": [ - "cmd", - "name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "args": { - "allOf": [ - { - "$ref": "#/definitions/ShellScopeEntryAllowedArgs" - } - ], - "description": "The allowed arguments for the command execution." - }, - "name": { - "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", - "type": "string" - }, - "sidecar": { - "description": "If this command is a sidecar command.", - "type": "boolean" - } - }, - "required": [ - "name", - "sidecar" - ], - "type": "object" - } - ], - "definitions": { - "ShellScopeEntryAllowedArg": { - "anyOf": [ - { - "description": "A non-configurable argument that is passed to the command in the order it was specified.", - "type": "string" - }, - { - "additionalProperties": false, - "description": "A variable that is set while calling the command from the webview API.", - "properties": { - "raw": { - "default": false, - "description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.", - "type": "boolean" - }, - "validator": { - "description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ", - "type": "string" - } - }, - "required": [ - "validator" - ], - "type": "object" - } - ], - "description": "A command argument allowed to be executed by the webview API." - }, - "ShellScopeEntryAllowedArgs": { - "anyOf": [ - { - "description": "Use a simple boolean to allow all or disable all arguments to this command configuration.", - "type": "boolean" - }, - { - "description": "A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.", - "items": { - "$ref": "#/definitions/ShellScopeEntryAllowedArg" - }, - "type": "array" - } - ], - "description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration." - } - }, - "description": "Shell scope entry.", - "title": "ShellScopeEntry" - } - }, - "updater": { - "default_permission": { - "identifier": "default", - "description": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n", - "permissions": [ - "allow-check", - "allow-download", - "allow-install", - "allow-download-and-install" - ] - }, - "permissions": { - "allow-check": { - "identifier": "allow-check", - "description": "Enables the check command without any pre-configured scope.", - "commands": { - "allow": [ - "check" - ], - "deny": [] - } - }, - "allow-download": { - "identifier": "allow-download", - "description": "Enables the download command without any pre-configured scope.", - "commands": { - "allow": [ - "download" - ], - "deny": [] - } - }, - "allow-download-and-install": { - "identifier": "allow-download-and-install", - "description": "Enables the download_and_install command without any pre-configured scope.", - "commands": { - "allow": [ - "download_and_install" - ], - "deny": [] - } - }, - "allow-install": { - "identifier": "allow-install", - "description": "Enables the install command without any pre-configured scope.", - "commands": { - "allow": [ - "install" - ], - "deny": [] - } - }, - "deny-check": { - "identifier": "deny-check", - "description": "Denies the check command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "check" - ] - } - }, - "deny-download": { - "identifier": "deny-download", - "description": "Denies the download command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "download" - ] - } - }, - "deny-download-and-install": { - "identifier": "deny-download-and-install", - "description": "Denies the download_and_install command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "download_and_install" - ] - } - }, - "deny-install": { - "identifier": "deny-install", - "description": "Denies the install command without any pre-configured scope.", - "commands": { - "allow": [], - "deny": [ - "install" - ] - } - } - }, - "permission_sets": {}, - "global_scope_schema": null - } -} \ No newline at end of file +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener","allow-supports-multiple-windows"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-supports-multiple-windows":{"identifier":"allow-supports-multiple-windows","description":"Enables the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":["supports_multiple_windows"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-supports-multiple-windows":{"identifier":"deny-supports-multiple-windows","description":"Denies the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["supports_multiple_windows"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-icon-with-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-icon-with-as-template":{"identifier":"allow-set-icon-with-as-template","description":"Enables the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_with_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-icon-with-as-template":{"identifier":"deny-set-icon-with-as-template","description":"Denies the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_with_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-activity-name","allow-scene-identifier","allow-internal-toggle-maximize"]},"permissions":{"allow-activity-name":{"identifier":"allow-activity-name","description":"Enables the activity_name command without any pre-configured scope.","commands":{"allow":["activity_name"],"deny":[]}},"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-scene-identifier":{"identifier":"allow-scene-identifier","description":"Enables the scene_identifier command without any pre-configured scope.","commands":{"allow":["scene_identifier"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-activity-name":{"identifier":"deny-activity-name","description":"Denies the activity_name command without any pre-configured scope.","commands":{"allow":[],"deny":["activity_name"]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-scene-identifier":{"identifier":"deny-scene-identifier","description":"Denies the scene_identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["scene_identifier"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)","commands":{"allow":["message"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)","commands":{"allow":["message"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)","commands":{"allow":[],"deny":["message"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)","commands":{"allow":[],"deny":["message"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"fs":{"default_permission":{"identifier":"default","description":"This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n","permissions":["create-app-specific-dirs","read-app-specific-dirs-recursive","deny-default"]},"permissions":{"allow-copy-file":{"identifier":"allow-copy-file","description":"Enables the copy_file command without any pre-configured scope.","commands":{"allow":["copy_file"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-exists":{"identifier":"allow-exists","description":"Enables the exists command without any pre-configured scope.","commands":{"allow":["exists"],"deny":[]}},"allow-fstat":{"identifier":"allow-fstat","description":"Enables the fstat command without any pre-configured scope.","commands":{"allow":["fstat"],"deny":[]}},"allow-ftruncate":{"identifier":"allow-ftruncate","description":"Enables the ftruncate command without any pre-configured scope.","commands":{"allow":["ftruncate"],"deny":[]}},"allow-lstat":{"identifier":"allow-lstat","description":"Enables the lstat command without any pre-configured scope.","commands":{"allow":["lstat"],"deny":[]}},"allow-mkdir":{"identifier":"allow-mkdir","description":"Enables the mkdir command without any pre-configured scope.","commands":{"allow":["mkdir"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-read":{"identifier":"allow-read","description":"Enables the read command without any pre-configured scope.","commands":{"allow":["read"],"deny":[]}},"allow-read-dir":{"identifier":"allow-read-dir","description":"Enables the read_dir command without any pre-configured scope.","commands":{"allow":["read_dir"],"deny":[]}},"allow-read-file":{"identifier":"allow-read-file","description":"Enables the read_file command without any pre-configured scope.","commands":{"allow":["read_file"],"deny":[]}},"allow-read-text-file":{"identifier":"allow-read-text-file","description":"Enables the read_text_file command without any pre-configured scope.","commands":{"allow":["read_text_file"],"deny":[]}},"allow-read-text-file-lines":{"identifier":"allow-read-text-file-lines","description":"Enables the read_text_file_lines command without any pre-configured scope.","commands":{"allow":["read_text_file_lines","read_text_file_lines_next"],"deny":[]}},"allow-read-text-file-lines-next":{"identifier":"allow-read-text-file-lines-next","description":"Enables the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":["read_text_file_lines_next"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-rename":{"identifier":"allow-rename","description":"Enables the rename command without any pre-configured scope.","commands":{"allow":["rename"],"deny":[]}},"allow-seek":{"identifier":"allow-seek","description":"Enables the seek command without any pre-configured scope.","commands":{"allow":["seek"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"allow-start-accessing-security-scoped-resource":{"identifier":"allow-start-accessing-security-scoped-resource","description":"Enables the start_accessing_security_scoped_resource command without any pre-configured scope.","commands":{"allow":["start_accessing_security_scoped_resource"],"deny":[]}},"allow-stat":{"identifier":"allow-stat","description":"Enables the stat command without any pre-configured scope.","commands":{"allow":["stat"],"deny":[]}},"allow-stop-accessing-security-scoped-resource":{"identifier":"allow-stop-accessing-security-scoped-resource","description":"Enables the stop_accessing_security_scoped_resource command without any pre-configured scope.","commands":{"allow":["stop_accessing_security_scoped_resource"],"deny":[]}},"allow-truncate":{"identifier":"allow-truncate","description":"Enables the truncate command without any pre-configured scope.","commands":{"allow":["truncate"],"deny":[]}},"allow-unwatch":{"identifier":"allow-unwatch","description":"Enables the unwatch command without any pre-configured scope.","commands":{"allow":["unwatch"],"deny":[]}},"allow-watch":{"identifier":"allow-watch","description":"Enables the watch command without any pre-configured scope.","commands":{"allow":["watch"],"deny":[]}},"allow-write":{"identifier":"allow-write","description":"Enables the write command without any pre-configured scope.","commands":{"allow":["write"],"deny":[]}},"allow-write-file":{"identifier":"allow-write-file","description":"Enables the write_file command without any pre-configured scope.","commands":{"allow":["write_file","open","write"],"deny":[]}},"allow-write-text-file":{"identifier":"allow-write-text-file","description":"Enables the write_text_file command without any pre-configured scope.","commands":{"allow":["write_text_file"],"deny":[]}},"create-app-specific-dirs":{"identifier":"create-app-specific-dirs","description":"This permissions allows to create the application specific directories.\n","commands":{"allow":["mkdir","scope-app-index"],"deny":[]}},"deny-copy-file":{"identifier":"deny-copy-file","description":"Denies the copy_file command without any pre-configured scope.","commands":{"allow":[],"deny":["copy_file"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-exists":{"identifier":"deny-exists","description":"Denies the exists command without any pre-configured scope.","commands":{"allow":[],"deny":["exists"]}},"deny-fstat":{"identifier":"deny-fstat","description":"Denies the fstat command without any pre-configured scope.","commands":{"allow":[],"deny":["fstat"]}},"deny-ftruncate":{"identifier":"deny-ftruncate","description":"Denies the ftruncate command without any pre-configured scope.","commands":{"allow":[],"deny":["ftruncate"]}},"deny-lstat":{"identifier":"deny-lstat","description":"Denies the lstat command without any pre-configured scope.","commands":{"allow":[],"deny":["lstat"]}},"deny-mkdir":{"identifier":"deny-mkdir","description":"Denies the mkdir command without any pre-configured scope.","commands":{"allow":[],"deny":["mkdir"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-read":{"identifier":"deny-read","description":"Denies the read command without any pre-configured scope.","commands":{"allow":[],"deny":["read"]}},"deny-read-dir":{"identifier":"deny-read-dir","description":"Denies the read_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["read_dir"]}},"deny-read-file":{"identifier":"deny-read-file","description":"Denies the read_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_file"]}},"deny-read-text-file":{"identifier":"deny-read-text-file","description":"Denies the read_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file"]}},"deny-read-text-file-lines":{"identifier":"deny-read-text-file-lines","description":"Denies the read_text_file_lines command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines"]}},"deny-read-text-file-lines-next":{"identifier":"deny-read-text-file-lines-next","description":"Denies the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines_next"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-rename":{"identifier":"deny-rename","description":"Denies the rename command without any pre-configured scope.","commands":{"allow":[],"deny":["rename"]}},"deny-seek":{"identifier":"deny-seek","description":"Denies the seek command without any pre-configured scope.","commands":{"allow":[],"deny":["seek"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}},"deny-start-accessing-security-scoped-resource":{"identifier":"deny-start-accessing-security-scoped-resource","description":"Denies the start_accessing_security_scoped_resource command without any pre-configured scope.","commands":{"allow":[],"deny":["start_accessing_security_scoped_resource"]}},"deny-stat":{"identifier":"deny-stat","description":"Denies the stat command without any pre-configured scope.","commands":{"allow":[],"deny":["stat"]}},"deny-stop-accessing-security-scoped-resource":{"identifier":"deny-stop-accessing-security-scoped-resource","description":"Denies the stop_accessing_security_scoped_resource command without any pre-configured scope.","commands":{"allow":[],"deny":["stop_accessing_security_scoped_resource"]}},"deny-truncate":{"identifier":"deny-truncate","description":"Denies the truncate command without any pre-configured scope.","commands":{"allow":[],"deny":["truncate"]}},"deny-unwatch":{"identifier":"deny-unwatch","description":"Denies the unwatch command without any pre-configured scope.","commands":{"allow":[],"deny":["unwatch"]}},"deny-watch":{"identifier":"deny-watch","description":"Denies the watch command without any pre-configured scope.","commands":{"allow":[],"deny":["watch"]}},"deny-webview-data-linux":{"identifier":"deny-webview-data-linux","description":"This denies read access to the\n`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-webview-data-windows":{"identifier":"deny-webview-data-windows","description":"This denies read access to the\n`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.\nAllowing access can lead to sensitive information disclosure and should be well considered.","commands":{"allow":[],"deny":[]}},"deny-write":{"identifier":"deny-write","description":"Denies the write command without any pre-configured scope.","commands":{"allow":[],"deny":["write"]}},"deny-write-file":{"identifier":"deny-write-file","description":"Denies the write_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_file"]}},"deny-write-text-file":{"identifier":"deny-write-text-file","description":"Denies the write_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["write_text_file"]}},"read-all":{"identifier":"read-all","description":"This enables all read related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists","watch","unwatch"],"deny":[]}},"read-app-specific-dirs-recursive":{"identifier":"read-app-specific-dirs-recursive","description":"This permission allows recursive read functionality on the application\nspecific base directories. \n","commands":{"allow":["read_dir","read_file","read_text_file","read_text_file_lines","read_text_file_lines_next","exists","scope-app-recursive"],"deny":[]}},"read-dirs":{"identifier":"read-dirs","description":"This enables directory read and file metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"deny":[]}},"read-files":{"identifier":"read-files","description":"This enables file read related commands without any pre-configured accessible paths.","commands":{"allow":["read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists"],"deny":[]}},"read-meta":{"identifier":"read-meta","description":"This enables all index or metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists","size"],"deny":[]}},"scope":{"identifier":"scope","description":"An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n","commands":{"allow":[],"deny":[]}},"scope-app":{"identifier":"scope-app","description":"This scope permits access to all files and list content of top level directories in the application folders.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"},{"path":"$APPDATA"},{"path":"$APPDATA/*"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"},{"path":"$APPCACHE"},{"path":"$APPCACHE/*"},{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the application directories.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete application folders, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"},{"path":"$APPDATA"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE"},{"path":"$APPCACHE/**"},{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-appcache":{"identifier":"scope-appcache","description":"This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/*"}]}},"scope-appcache-index":{"identifier":"scope-appcache-index","description":"This scope permits to list all files and folders in the `$APPCACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"}]}},"scope-appcache-recursive":{"identifier":"scope-appcache-recursive","description":"This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/**"}]}},"scope-appconfig":{"identifier":"scope-appconfig","description":"This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"}]}},"scope-appconfig-index":{"identifier":"scope-appconfig-index","description":"This scope permits to list all files and folders in the `$APPCONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"}]}},"scope-appconfig-recursive":{"identifier":"scope-appconfig-recursive","description":"This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"}]}},"scope-appdata":{"identifier":"scope-appdata","description":"This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/*"}]}},"scope-appdata-index":{"identifier":"scope-appdata-index","description":"This scope permits to list all files and folders in the `$APPDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"}]}},"scope-appdata-recursive":{"identifier":"scope-appdata-recursive","description":"This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]}},"scope-applocaldata":{"identifier":"scope-applocaldata","description":"This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"}]}},"scope-applocaldata-index":{"identifier":"scope-applocaldata-index","description":"This scope permits to list all files and folders in the `$APPLOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"}]}},"scope-applocaldata-recursive":{"identifier":"scope-applocaldata-recursive","description":"This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"}]}},"scope-applog":{"identifier":"scope-applog","description":"This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-applog-index":{"identifier":"scope-applog-index","description":"This scope permits to list all files and folders in the `$APPLOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"}]}},"scope-applog-recursive":{"identifier":"scope-applog-recursive","description":"This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-audio":{"identifier":"scope-audio","description":"This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/*"}]}},"scope-audio-index":{"identifier":"scope-audio-index","description":"This scope permits to list all files and folders in the `$AUDIO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"}]}},"scope-audio-recursive":{"identifier":"scope-audio-recursive","description":"This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/**"}]}},"scope-cache":{"identifier":"scope-cache","description":"This scope permits access to all files and list content of top level directories in the `$CACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/*"}]}},"scope-cache-index":{"identifier":"scope-cache-index","description":"This scope permits to list all files and folders in the `$CACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"}]}},"scope-cache-recursive":{"identifier":"scope-cache-recursive","description":"This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/**"}]}},"scope-config":{"identifier":"scope-config","description":"This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/*"}]}},"scope-config-index":{"identifier":"scope-config-index","description":"This scope permits to list all files and folders in the `$CONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"}]}},"scope-config-recursive":{"identifier":"scope-config-recursive","description":"This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/**"}]}},"scope-data":{"identifier":"scope-data","description":"This scope permits access to all files and list content of top level directories in the `$DATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/*"}]}},"scope-data-index":{"identifier":"scope-data-index","description":"This scope permits to list all files and folders in the `$DATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"}]}},"scope-data-recursive":{"identifier":"scope-data-recursive","description":"This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/**"}]}},"scope-desktop":{"identifier":"scope-desktop","description":"This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/*"}]}},"scope-desktop-index":{"identifier":"scope-desktop-index","description":"This scope permits to list all files and folders in the `$DESKTOP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"}]}},"scope-desktop-recursive":{"identifier":"scope-desktop-recursive","description":"This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/**"}]}},"scope-document":{"identifier":"scope-document","description":"This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/*"}]}},"scope-document-index":{"identifier":"scope-document-index","description":"This scope permits to list all files and folders in the `$DOCUMENT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"}]}},"scope-document-recursive":{"identifier":"scope-document-recursive","description":"This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/**"}]}},"scope-download":{"identifier":"scope-download","description":"This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/*"}]}},"scope-download-index":{"identifier":"scope-download-index","description":"This scope permits to list all files and folders in the `$DOWNLOAD`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"}]}},"scope-download-recursive":{"identifier":"scope-download-recursive","description":"This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/**"}]}},"scope-exe":{"identifier":"scope-exe","description":"This scope permits access to all files and list content of top level directories in the `$EXE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/*"}]}},"scope-exe-index":{"identifier":"scope-exe-index","description":"This scope permits to list all files and folders in the `$EXE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"}]}},"scope-exe-recursive":{"identifier":"scope-exe-recursive","description":"This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/**"}]}},"scope-font":{"identifier":"scope-font","description":"This scope permits access to all files and list content of top level directories in the `$FONT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/*"}]}},"scope-font-index":{"identifier":"scope-font-index","description":"This scope permits to list all files and folders in the `$FONT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"}]}},"scope-font-recursive":{"identifier":"scope-font-recursive","description":"This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/**"}]}},"scope-home":{"identifier":"scope-home","description":"This scope permits access to all files and list content of top level directories in the `$HOME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/*"}]}},"scope-home-index":{"identifier":"scope-home-index","description":"This scope permits to list all files and folders in the `$HOME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"}]}},"scope-home-recursive":{"identifier":"scope-home-recursive","description":"This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/**"}]}},"scope-localdata":{"identifier":"scope-localdata","description":"This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/*"}]}},"scope-localdata-index":{"identifier":"scope-localdata-index","description":"This scope permits to list all files and folders in the `$LOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"}]}},"scope-localdata-recursive":{"identifier":"scope-localdata-recursive","description":"This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/**"}]}},"scope-log":{"identifier":"scope-log","description":"This scope permits access to all files and list content of top level directories in the `$LOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/*"}]}},"scope-log-index":{"identifier":"scope-log-index","description":"This scope permits to list all files and folders in the `$LOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"}]}},"scope-log-recursive":{"identifier":"scope-log-recursive","description":"This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/**"}]}},"scope-picture":{"identifier":"scope-picture","description":"This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/*"}]}},"scope-picture-index":{"identifier":"scope-picture-index","description":"This scope permits to list all files and folders in the `$PICTURE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"}]}},"scope-picture-recursive":{"identifier":"scope-picture-recursive","description":"This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/**"}]}},"scope-public":{"identifier":"scope-public","description":"This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/*"}]}},"scope-public-index":{"identifier":"scope-public-index","description":"This scope permits to list all files and folders in the `$PUBLIC`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"}]}},"scope-public-recursive":{"identifier":"scope-public-recursive","description":"This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/**"}]}},"scope-resource":{"identifier":"scope-resource","description":"This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/*"}]}},"scope-resource-index":{"identifier":"scope-resource-index","description":"This scope permits to list all files and folders in the `$RESOURCE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"}]}},"scope-resource-recursive":{"identifier":"scope-resource-recursive","description":"This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/**"}]}},"scope-runtime":{"identifier":"scope-runtime","description":"This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/*"}]}},"scope-runtime-index":{"identifier":"scope-runtime-index","description":"This scope permits to list all files and folders in the `$RUNTIME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"}]}},"scope-runtime-recursive":{"identifier":"scope-runtime-recursive","description":"This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/**"}]}},"scope-temp":{"identifier":"scope-temp","description":"This scope permits access to all files and list content of top level directories in the `$TEMP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/*"}]}},"scope-temp-index":{"identifier":"scope-temp-index","description":"This scope permits to list all files and folders in the `$TEMP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"}]}},"scope-temp-recursive":{"identifier":"scope-temp-recursive","description":"This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/**"}]}},"scope-template":{"identifier":"scope-template","description":"This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/*"}]}},"scope-template-index":{"identifier":"scope-template-index","description":"This scope permits to list all files and folders in the `$TEMPLATE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"}]}},"scope-template-recursive":{"identifier":"scope-template-recursive","description":"This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/**"}]}},"scope-video":{"identifier":"scope-video","description":"This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/*"}]}},"scope-video-index":{"identifier":"scope-video-index","description":"This scope permits to list all files and folders in the `$VIDEO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"}]}},"scope-video-recursive":{"identifier":"scope-video-recursive","description":"This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/**"}]}},"write-all":{"identifier":"write-all","description":"This enables all write related commands without any pre-configured accessible paths.","commands":{"allow":["mkdir","create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}},"write-files":{"identifier":"write-files","description":"This enables all file write related commands without any pre-configured accessible paths.","commands":{"allow":["create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}}},"permission_sets":{"allow-app-meta":{"identifier":"allow-app-meta","description":"This allows non-recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-index"]},"allow-app-meta-recursive":{"identifier":"allow-app-meta-recursive","description":"This allows full recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-recursive"]},"allow-app-read":{"identifier":"allow-app-read","description":"This allows non-recursive read access to the application folders.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete application folders, files and subdirectories.","permissions":["read-all","scope-app-recursive"]},"allow-app-write":{"identifier":"allow-app-write","description":"This allows non-recursive write access to the application folders.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete application folders, files and subdirectories.","permissions":["write-all","scope-app-recursive"]},"allow-appcache-meta":{"identifier":"allow-appcache-meta","description":"This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-index"]},"allow-appcache-meta-recursive":{"identifier":"allow-appcache-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-recursive"]},"allow-appcache-read":{"identifier":"allow-appcache-read","description":"This allows non-recursive read access to the `$APPCACHE` folder.","permissions":["read-all","scope-appcache"]},"allow-appcache-read-recursive":{"identifier":"allow-appcache-read-recursive","description":"This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["read-all","scope-appcache-recursive"]},"allow-appcache-write":{"identifier":"allow-appcache-write","description":"This allows non-recursive write access to the `$APPCACHE` folder.","permissions":["write-all","scope-appcache"]},"allow-appcache-write-recursive":{"identifier":"allow-appcache-write-recursive","description":"This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["write-all","scope-appcache-recursive"]},"allow-appconfig-meta":{"identifier":"allow-appconfig-meta","description":"This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-index"]},"allow-appconfig-meta-recursive":{"identifier":"allow-appconfig-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-recursive"]},"allow-appconfig-read":{"identifier":"allow-appconfig-read","description":"This allows non-recursive read access to the `$APPCONFIG` folder.","permissions":["read-all","scope-appconfig"]},"allow-appconfig-read-recursive":{"identifier":"allow-appconfig-read-recursive","description":"This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["read-all","scope-appconfig-recursive"]},"allow-appconfig-write":{"identifier":"allow-appconfig-write","description":"This allows non-recursive write access to the `$APPCONFIG` folder.","permissions":["write-all","scope-appconfig"]},"allow-appconfig-write-recursive":{"identifier":"allow-appconfig-write-recursive","description":"This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["write-all","scope-appconfig-recursive"]},"allow-appdata-meta":{"identifier":"allow-appdata-meta","description":"This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-index"]},"allow-appdata-meta-recursive":{"identifier":"allow-appdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-recursive"]},"allow-appdata-read":{"identifier":"allow-appdata-read","description":"This allows non-recursive read access to the `$APPDATA` folder.","permissions":["read-all","scope-appdata"]},"allow-appdata-read-recursive":{"identifier":"allow-appdata-read-recursive","description":"This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["read-all","scope-appdata-recursive"]},"allow-appdata-write":{"identifier":"allow-appdata-write","description":"This allows non-recursive write access to the `$APPDATA` folder.","permissions":["write-all","scope-appdata"]},"allow-appdata-write-recursive":{"identifier":"allow-appdata-write-recursive","description":"This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["write-all","scope-appdata-recursive"]},"allow-applocaldata-meta":{"identifier":"allow-applocaldata-meta","description":"This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-index"]},"allow-applocaldata-meta-recursive":{"identifier":"allow-applocaldata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-recursive"]},"allow-applocaldata-read":{"identifier":"allow-applocaldata-read","description":"This allows non-recursive read access to the `$APPLOCALDATA` folder.","permissions":["read-all","scope-applocaldata"]},"allow-applocaldata-read-recursive":{"identifier":"allow-applocaldata-read-recursive","description":"This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-applocaldata-recursive"]},"allow-applocaldata-write":{"identifier":"allow-applocaldata-write","description":"This allows non-recursive write access to the `$APPLOCALDATA` folder.","permissions":["write-all","scope-applocaldata"]},"allow-applocaldata-write-recursive":{"identifier":"allow-applocaldata-write-recursive","description":"This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-applocaldata-recursive"]},"allow-applog-meta":{"identifier":"allow-applog-meta","description":"This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-index"]},"allow-applog-meta-recursive":{"identifier":"allow-applog-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-recursive"]},"allow-applog-read":{"identifier":"allow-applog-read","description":"This allows non-recursive read access to the `$APPLOG` folder.","permissions":["read-all","scope-applog"]},"allow-applog-read-recursive":{"identifier":"allow-applog-read-recursive","description":"This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["read-all","scope-applog-recursive"]},"allow-applog-write":{"identifier":"allow-applog-write","description":"This allows non-recursive write access to the `$APPLOG` folder.","permissions":["write-all","scope-applog"]},"allow-applog-write-recursive":{"identifier":"allow-applog-write-recursive","description":"This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["write-all","scope-applog-recursive"]},"allow-audio-meta":{"identifier":"allow-audio-meta","description":"This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-index"]},"allow-audio-meta-recursive":{"identifier":"allow-audio-meta-recursive","description":"This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-recursive"]},"allow-audio-read":{"identifier":"allow-audio-read","description":"This allows non-recursive read access to the `$AUDIO` folder.","permissions":["read-all","scope-audio"]},"allow-audio-read-recursive":{"identifier":"allow-audio-read-recursive","description":"This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["read-all","scope-audio-recursive"]},"allow-audio-write":{"identifier":"allow-audio-write","description":"This allows non-recursive write access to the `$AUDIO` folder.","permissions":["write-all","scope-audio"]},"allow-audio-write-recursive":{"identifier":"allow-audio-write-recursive","description":"This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["write-all","scope-audio-recursive"]},"allow-cache-meta":{"identifier":"allow-cache-meta","description":"This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-index"]},"allow-cache-meta-recursive":{"identifier":"allow-cache-meta-recursive","description":"This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-recursive"]},"allow-cache-read":{"identifier":"allow-cache-read","description":"This allows non-recursive read access to the `$CACHE` folder.","permissions":["read-all","scope-cache"]},"allow-cache-read-recursive":{"identifier":"allow-cache-read-recursive","description":"This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.","permissions":["read-all","scope-cache-recursive"]},"allow-cache-write":{"identifier":"allow-cache-write","description":"This allows non-recursive write access to the `$CACHE` folder.","permissions":["write-all","scope-cache"]},"allow-cache-write-recursive":{"identifier":"allow-cache-write-recursive","description":"This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.","permissions":["write-all","scope-cache-recursive"]},"allow-config-meta":{"identifier":"allow-config-meta","description":"This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-index"]},"allow-config-meta-recursive":{"identifier":"allow-config-meta-recursive","description":"This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-recursive"]},"allow-config-read":{"identifier":"allow-config-read","description":"This allows non-recursive read access to the `$CONFIG` folder.","permissions":["read-all","scope-config"]},"allow-config-read-recursive":{"identifier":"allow-config-read-recursive","description":"This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["read-all","scope-config-recursive"]},"allow-config-write":{"identifier":"allow-config-write","description":"This allows non-recursive write access to the `$CONFIG` folder.","permissions":["write-all","scope-config"]},"allow-config-write-recursive":{"identifier":"allow-config-write-recursive","description":"This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["write-all","scope-config-recursive"]},"allow-data-meta":{"identifier":"allow-data-meta","description":"This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-index"]},"allow-data-meta-recursive":{"identifier":"allow-data-meta-recursive","description":"This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-recursive"]},"allow-data-read":{"identifier":"allow-data-read","description":"This allows non-recursive read access to the `$DATA` folder.","permissions":["read-all","scope-data"]},"allow-data-read-recursive":{"identifier":"allow-data-read-recursive","description":"This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.","permissions":["read-all","scope-data-recursive"]},"allow-data-write":{"identifier":"allow-data-write","description":"This allows non-recursive write access to the `$DATA` folder.","permissions":["write-all","scope-data"]},"allow-data-write-recursive":{"identifier":"allow-data-write-recursive","description":"This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.","permissions":["write-all","scope-data-recursive"]},"allow-desktop-meta":{"identifier":"allow-desktop-meta","description":"This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-index"]},"allow-desktop-meta-recursive":{"identifier":"allow-desktop-meta-recursive","description":"This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-recursive"]},"allow-desktop-read":{"identifier":"allow-desktop-read","description":"This allows non-recursive read access to the `$DESKTOP` folder.","permissions":["read-all","scope-desktop"]},"allow-desktop-read-recursive":{"identifier":"allow-desktop-read-recursive","description":"This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["read-all","scope-desktop-recursive"]},"allow-desktop-write":{"identifier":"allow-desktop-write","description":"This allows non-recursive write access to the `$DESKTOP` folder.","permissions":["write-all","scope-desktop"]},"allow-desktop-write-recursive":{"identifier":"allow-desktop-write-recursive","description":"This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["write-all","scope-desktop-recursive"]},"allow-document-meta":{"identifier":"allow-document-meta","description":"This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-index"]},"allow-document-meta-recursive":{"identifier":"allow-document-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-recursive"]},"allow-document-read":{"identifier":"allow-document-read","description":"This allows non-recursive read access to the `$DOCUMENT` folder.","permissions":["read-all","scope-document"]},"allow-document-read-recursive":{"identifier":"allow-document-read-recursive","description":"This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["read-all","scope-document-recursive"]},"allow-document-write":{"identifier":"allow-document-write","description":"This allows non-recursive write access to the `$DOCUMENT` folder.","permissions":["write-all","scope-document"]},"allow-document-write-recursive":{"identifier":"allow-document-write-recursive","description":"This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["write-all","scope-document-recursive"]},"allow-download-meta":{"identifier":"allow-download-meta","description":"This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-index"]},"allow-download-meta-recursive":{"identifier":"allow-download-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-recursive"]},"allow-download-read":{"identifier":"allow-download-read","description":"This allows non-recursive read access to the `$DOWNLOAD` folder.","permissions":["read-all","scope-download"]},"allow-download-read-recursive":{"identifier":"allow-download-read-recursive","description":"This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["read-all","scope-download-recursive"]},"allow-download-write":{"identifier":"allow-download-write","description":"This allows non-recursive write access to the `$DOWNLOAD` folder.","permissions":["write-all","scope-download"]},"allow-download-write-recursive":{"identifier":"allow-download-write-recursive","description":"This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["write-all","scope-download-recursive"]},"allow-exe-meta":{"identifier":"allow-exe-meta","description":"This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-index"]},"allow-exe-meta-recursive":{"identifier":"allow-exe-meta-recursive","description":"This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-recursive"]},"allow-exe-read":{"identifier":"allow-exe-read","description":"This allows non-recursive read access to the `$EXE` folder.","permissions":["read-all","scope-exe"]},"allow-exe-read-recursive":{"identifier":"allow-exe-read-recursive","description":"This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.","permissions":["read-all","scope-exe-recursive"]},"allow-exe-write":{"identifier":"allow-exe-write","description":"This allows non-recursive write access to the `$EXE` folder.","permissions":["write-all","scope-exe"]},"allow-exe-write-recursive":{"identifier":"allow-exe-write-recursive","description":"This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.","permissions":["write-all","scope-exe-recursive"]},"allow-font-meta":{"identifier":"allow-font-meta","description":"This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-index"]},"allow-font-meta-recursive":{"identifier":"allow-font-meta-recursive","description":"This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-recursive"]},"allow-font-read":{"identifier":"allow-font-read","description":"This allows non-recursive read access to the `$FONT` folder.","permissions":["read-all","scope-font"]},"allow-font-read-recursive":{"identifier":"allow-font-read-recursive","description":"This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.","permissions":["read-all","scope-font-recursive"]},"allow-font-write":{"identifier":"allow-font-write","description":"This allows non-recursive write access to the `$FONT` folder.","permissions":["write-all","scope-font"]},"allow-font-write-recursive":{"identifier":"allow-font-write-recursive","description":"This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.","permissions":["write-all","scope-font-recursive"]},"allow-home-meta":{"identifier":"allow-home-meta","description":"This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-index"]},"allow-home-meta-recursive":{"identifier":"allow-home-meta-recursive","description":"This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-recursive"]},"allow-home-read":{"identifier":"allow-home-read","description":"This allows non-recursive read access to the `$HOME` folder.","permissions":["read-all","scope-home"]},"allow-home-read-recursive":{"identifier":"allow-home-read-recursive","description":"This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.","permissions":["read-all","scope-home-recursive"]},"allow-home-write":{"identifier":"allow-home-write","description":"This allows non-recursive write access to the `$HOME` folder.","permissions":["write-all","scope-home"]},"allow-home-write-recursive":{"identifier":"allow-home-write-recursive","description":"This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.","permissions":["write-all","scope-home-recursive"]},"allow-localdata-meta":{"identifier":"allow-localdata-meta","description":"This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-index"]},"allow-localdata-meta-recursive":{"identifier":"allow-localdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-recursive"]},"allow-localdata-read":{"identifier":"allow-localdata-read","description":"This allows non-recursive read access to the `$LOCALDATA` folder.","permissions":["read-all","scope-localdata"]},"allow-localdata-read-recursive":{"identifier":"allow-localdata-read-recursive","description":"This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-localdata-recursive"]},"allow-localdata-write":{"identifier":"allow-localdata-write","description":"This allows non-recursive write access to the `$LOCALDATA` folder.","permissions":["write-all","scope-localdata"]},"allow-localdata-write-recursive":{"identifier":"allow-localdata-write-recursive","description":"This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-localdata-recursive"]},"allow-log-meta":{"identifier":"allow-log-meta","description":"This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-index"]},"allow-log-meta-recursive":{"identifier":"allow-log-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-recursive"]},"allow-log-read":{"identifier":"allow-log-read","description":"This allows non-recursive read access to the `$LOG` folder.","permissions":["read-all","scope-log"]},"allow-log-read-recursive":{"identifier":"allow-log-read-recursive","description":"This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.","permissions":["read-all","scope-log-recursive"]},"allow-log-write":{"identifier":"allow-log-write","description":"This allows non-recursive write access to the `$LOG` folder.","permissions":["write-all","scope-log"]},"allow-log-write-recursive":{"identifier":"allow-log-write-recursive","description":"This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.","permissions":["write-all","scope-log-recursive"]},"allow-picture-meta":{"identifier":"allow-picture-meta","description":"This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-index"]},"allow-picture-meta-recursive":{"identifier":"allow-picture-meta-recursive","description":"This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-recursive"]},"allow-picture-read":{"identifier":"allow-picture-read","description":"This allows non-recursive read access to the `$PICTURE` folder.","permissions":["read-all","scope-picture"]},"allow-picture-read-recursive":{"identifier":"allow-picture-read-recursive","description":"This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["read-all","scope-picture-recursive"]},"allow-picture-write":{"identifier":"allow-picture-write","description":"This allows non-recursive write access to the `$PICTURE` folder.","permissions":["write-all","scope-picture"]},"allow-picture-write-recursive":{"identifier":"allow-picture-write-recursive","description":"This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["write-all","scope-picture-recursive"]},"allow-public-meta":{"identifier":"allow-public-meta","description":"This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-index"]},"allow-public-meta-recursive":{"identifier":"allow-public-meta-recursive","description":"This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-recursive"]},"allow-public-read":{"identifier":"allow-public-read","description":"This allows non-recursive read access to the `$PUBLIC` folder.","permissions":["read-all","scope-public"]},"allow-public-read-recursive":{"identifier":"allow-public-read-recursive","description":"This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["read-all","scope-public-recursive"]},"allow-public-write":{"identifier":"allow-public-write","description":"This allows non-recursive write access to the `$PUBLIC` folder.","permissions":["write-all","scope-public"]},"allow-public-write-recursive":{"identifier":"allow-public-write-recursive","description":"This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["write-all","scope-public-recursive"]},"allow-resource-meta":{"identifier":"allow-resource-meta","description":"This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-index"]},"allow-resource-meta-recursive":{"identifier":"allow-resource-meta-recursive","description":"This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-recursive"]},"allow-resource-read":{"identifier":"allow-resource-read","description":"This allows non-recursive read access to the `$RESOURCE` folder.","permissions":["read-all","scope-resource"]},"allow-resource-read-recursive":{"identifier":"allow-resource-read-recursive","description":"This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["read-all","scope-resource-recursive"]},"allow-resource-write":{"identifier":"allow-resource-write","description":"This allows non-recursive write access to the `$RESOURCE` folder.","permissions":["write-all","scope-resource"]},"allow-resource-write-recursive":{"identifier":"allow-resource-write-recursive","description":"This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["write-all","scope-resource-recursive"]},"allow-runtime-meta":{"identifier":"allow-runtime-meta","description":"This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-index"]},"allow-runtime-meta-recursive":{"identifier":"allow-runtime-meta-recursive","description":"This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-recursive"]},"allow-runtime-read":{"identifier":"allow-runtime-read","description":"This allows non-recursive read access to the `$RUNTIME` folder.","permissions":["read-all","scope-runtime"]},"allow-runtime-read-recursive":{"identifier":"allow-runtime-read-recursive","description":"This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["read-all","scope-runtime-recursive"]},"allow-runtime-write":{"identifier":"allow-runtime-write","description":"This allows non-recursive write access to the `$RUNTIME` folder.","permissions":["write-all","scope-runtime"]},"allow-runtime-write-recursive":{"identifier":"allow-runtime-write-recursive","description":"This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["write-all","scope-runtime-recursive"]},"allow-temp-meta":{"identifier":"allow-temp-meta","description":"This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-index"]},"allow-temp-meta-recursive":{"identifier":"allow-temp-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-recursive"]},"allow-temp-read":{"identifier":"allow-temp-read","description":"This allows non-recursive read access to the `$TEMP` folder.","permissions":["read-all","scope-temp"]},"allow-temp-read-recursive":{"identifier":"allow-temp-read-recursive","description":"This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.","permissions":["read-all","scope-temp-recursive"]},"allow-temp-write":{"identifier":"allow-temp-write","description":"This allows non-recursive write access to the `$TEMP` folder.","permissions":["write-all","scope-temp"]},"allow-temp-write-recursive":{"identifier":"allow-temp-write-recursive","description":"This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.","permissions":["write-all","scope-temp-recursive"]},"allow-template-meta":{"identifier":"allow-template-meta","description":"This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-index"]},"allow-template-meta-recursive":{"identifier":"allow-template-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-recursive"]},"allow-template-read":{"identifier":"allow-template-read","description":"This allows non-recursive read access to the `$TEMPLATE` folder.","permissions":["read-all","scope-template"]},"allow-template-read-recursive":{"identifier":"allow-template-read-recursive","description":"This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["read-all","scope-template-recursive"]},"allow-template-write":{"identifier":"allow-template-write","description":"This allows non-recursive write access to the `$TEMPLATE` folder.","permissions":["write-all","scope-template"]},"allow-template-write-recursive":{"identifier":"allow-template-write-recursive","description":"This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["write-all","scope-template-recursive"]},"allow-video-meta":{"identifier":"allow-video-meta","description":"This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-index"]},"allow-video-meta-recursive":{"identifier":"allow-video-meta-recursive","description":"This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-recursive"]},"allow-video-read":{"identifier":"allow-video-read","description":"This allows non-recursive read access to the `$VIDEO` folder.","permissions":["read-all","scope-video"]},"allow-video-read-recursive":{"identifier":"allow-video-read-recursive","description":"This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["read-all","scope-video-recursive"]},"allow-video-write":{"identifier":"allow-video-write","description":"This allows non-recursive write access to the `$VIDEO` folder.","permissions":["write-all","scope-video"]},"allow-video-write-recursive":{"identifier":"allow-video-write-recursive","description":"This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["write-all","scope-video-recursive"]},"deny-default":{"identifier":"deny-default","description":"This denies access to dangerous Tauri relevant files and folders by default.","permissions":["deny-webview-data-linux","deny-webview-data-windows"]}},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A path that can be accessed by the webview when using the fs APIs. FS scope path pattern.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},{"properties":{"path":{"description":"A path that can be accessed by the webview when using the fs APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"log":{"default_permission":{"identifier":"default","description":"Allows the log command","permissions":["allow-log"]},"permissions":{"allow-log":{"identifier":"allow-log","description":"Enables the log command without any pre-configured scope.","commands":{"allow":["log"],"deny":[]}},"deny-log":{"identifier":"deny-log","description":"Denies the log command without any pre-configured scope.","commands":{"allow":[],"deny":["log"]}}},"permission_sets":{},"global_scope_schema":null},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}},"updater":{"default_permission":{"identifier":"default","description":"This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n","permissions":["allow-check","allow-download","allow-install","allow-download-and-install"]},"permissions":{"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-download-and-install":{"identifier":"allow-download-and-install","description":"Enables the download_and_install command without any pre-configured scope.","commands":{"allow":["download_and_install"],"deny":[]}},"allow-install":{"identifier":"allow-install","description":"Enables the install command without any pre-configured scope.","commands":{"allow":["install"],"deny":[]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-download-and-install":{"identifier":"deny-download-and-install","description":"Denies the download_and_install command without any pre-configured scope.","commands":{"allow":[],"deny":["download_and_install"]}},"deny-install":{"identifier":"deny-install","description":"Denies the install command without any pre-configured scope.","commands":{"allow":[],"deny":["install"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json index 9e26dfe..03348ae 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{} \ No newline at end of file +{"default":{"identifier":"default","description":"Default capabilities for Praetorian","local":true,"windows":["main"],"permissions":["core:default","dialog:allow-open","dialog:allow-save","fs:default","shell:default"]}} \ No newline at end of file diff --git a/src-tauri/src/catalog/manager.rs b/src-tauri/src/catalog/manager.rs index 4ce275d..c7c5f09 100644 --- a/src-tauri/src/catalog/manager.rs +++ b/src-tauri/src/catalog/manager.rs @@ -1,10 +1,11 @@ use std::path::{Path, PathBuf}; use std::fs; -use sqlx::{SqlitePool, FromRow}; +use sqlx::{SqlitePool, FromRow, Row}; use sha2::{Sha256, Digest}; use walkdir::WalkDir; use anyhow::{Context, Result}; +use serde::Serialize; use crate::db::Database; use crate::exif::parser::ExifParser; @@ -15,7 +16,7 @@ const SUPPORTED_EXTENSIONS: &[&str] = &[ "arw", "cr3", "cr2", "nef", "orf", "sr2", "dng", "raf", ]; -#[derive(Debug, FromRow)] +#[derive(Debug, FromRow, serde::Serialize)] pub struct ImageRecord { pub id: i64, pub folder_id: Option, @@ -35,7 +36,7 @@ pub struct ImageRecord { pub is_missing: bool, } -#[derive(Debug, FromRow)] +#[derive(Debug, FromRow, serde::Serialize)] pub struct FolderRecord { pub id: i64, pub path: String, @@ -45,6 +46,77 @@ pub struct FolderRecord { pub is_watched: bool, } +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct ExifRecord { + pub image_id: i64, + pub camera_make: Option, + pub camera_model: Option, + pub lens_model: Option, + pub iso: Option, + pub aperture_f_number: Option, + pub shutter_speed_num: Option, + pub shutter_speed_den: Option, + pub focal_length_mm: Option, + pub gps_latitude: Option, + pub gps_longitude: Option, + pub gps_altitude: Option, +} + +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct PersonRecord { + pub id: i64, + pub name: String, + pub created_at: String, + pub updated_at: String, + pub face_count: i64, +} + +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct FaceRecord { + pub id: i64, + pub image_id: i64, + pub person_id: Option, + pub bbox_x: f64, + pub bbox_y: f64, + pub bbox_width: f64, + pub bbox_height: f64, + pub confidence: f64, +} + +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct TagRecord { + pub id: i64, + pub name: String, + pub color: Option, +} + +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct AlbumRecord { + pub id: i64, + pub name: String, + pub description: Option, + pub created_at: String, +} + +#[derive(Debug, FromRow, Clone, Serialize)] +pub struct ImageWithTag { + pub id: i64, + pub file_path: String, + pub file_name: String, + pub tag_name: String, +} + +#[derive(Debug, Serialize)] +pub struct CatalogStats { + pub total_images: i64, + pub total_faces: i64, + pub total_people: i64, + pub total_folders: i64, + pub total_tags: i64, + pub unindexed_faces: i64, + pub missing_files: i64, +} + pub struct CatalogManager { pub db: Database, pub cache_dir: PathBuf, @@ -66,7 +138,11 @@ impl CatalogManager { fs::create_dir_all(&cache_dir).context("Failed to create cache directory")?; let exif_parser = ExifParser::new(); - let image_pipeline = ImagePipeline::new(cache_dir.clone()); + let pool = db.pool(); + let mut image_pipeline = ImagePipeline::new(cache_dir.clone()); + + // Start the background worker with a cloned pool + image_pipeline.start(pool.clone()); Ok(Self { db, @@ -116,7 +192,10 @@ impl CatalogManager { // Skip if already cataloged let exists: bool = sqlx::query_scalar( - "SELECT EXISTS(SELECT 1 FROM images WHERE file_path = ?)", + r#"SELECT EXISTS( + SELECT 1 FROM images WHERE file_path = ? + ) + "#, ) .bind(&file_path) .fetch_one(pool) @@ -161,7 +240,7 @@ impl CatalogManager { .to_string() .to_lowercase(); - let file_hash = self.compute_file_hash(file_path)?; + let file_hash = Self::compute_file_hash(file_path)?; // Parse EXIF metadata let exif = self.exif_parser @@ -169,7 +248,7 @@ impl CatalogManager { .unwrap_or_default(); // Insert image record - let result = sqlx::query!( + let result = sqlx::query( r#" INSERT INTO images ( folder_id, @@ -183,23 +262,23 @@ impl CatalogManager { file_hash ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "#, - folder_id, - file_path, - file_name, - file_extension, - metadata.len() as i64, - exif.width as Option, - exif.height as Option, - exif.date_time_original.as_deref(), - file_hash, ) + .bind(folder_id) + .bind(file_path) + .bind(file_name) + .bind(file_extension) + .bind(metadata.len() as i64) + .bind(exif.width.map(|w| w as i32)) + .bind(exif.height.map(|h| h as i32)) + .bind(exif.date_time_original.as_deref()) + .bind(file_hash) .execute(pool) .await?; let image_id = result.last_insert_rowid(); // Insert EXIF data - sqlx::query!( + sqlx::query( r#" INSERT INTO exif_data ( image_id, @@ -216,19 +295,19 @@ impl CatalogManager { gps_altitude ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "#, - image_id, - exif.camera_make.as_deref(), - exif.camera_model.as_deref(), - exif.lens_model.as_deref(), - exif.iso as Option, - exif.aperture, - exif.shutter_num as Option, - exif.shutter_den as Option, - exif.focal_length, - exif.gps_latitude, - exif.gps_longitude, - exif.gps_altitude, ) + .bind(image_id) + .bind(exif.camera_make.as_deref()) + .bind(exif.camera_model.as_deref()) + .bind(exif.lens_model.as_deref()) + .bind(exif.iso.map(|i| i as i32)) + .bind(exif.aperture) + .bind(exif.shutter_num.map(|n| n as i32)) + .bind(exif.shutter_den.map(|d| d as i32)) + .bind(exif.focal_length) + .bind(exif.gps_latitude) + .bind(exif.gps_longitude) + .bind(exif.gps_altitude) .execute(pool) .await?; @@ -256,11 +335,11 @@ impl CatalogManager { return Ok(id); } - let result = sqlx::query!( + let result = sqlx::query( "INSERT INTO folders (path, name) VALUES (?, ?)", - path, - folder_name, ) + .bind(path) + .bind(folder_name) .execute(pool) .await?; @@ -270,10 +349,10 @@ impl CatalogManager { async fn queue_thumbnail( &self, image_id: i64, - file_path: &str, + _file_path: &str, pool: &SqlitePool, ) -> Result<()> { - sqlx::query!( + sqlx::query( r#" INSERT INTO processing_queue ( image_id, @@ -282,14 +361,13 @@ impl CatalogManager { ) VALUES (?, 'thumbnail', 10) "#, - image_id, - file_path, ) + .bind(image_id) .execute(pool) .await?; // Also queue smart preview - sqlx::query!( + sqlx::query( r#" INSERT INTO processing_queue ( image_id, @@ -298,8 +376,8 @@ impl CatalogManager { ) VALUES (?, 'preview', 5) "#, - image_id, ) + .bind(image_id) .execute(pool) .await?; @@ -342,12 +420,13 @@ impl CatalogManager { is_missing FROM images WHERE is_archived = 0 - AND ($1 IS NULL OR rating = $1) + AND (? IS NULL OR rating = ?) ORDER BY date_taken DESC LIMIT ? OFFSET ? "#, ) .bind(rating_filter) + .bind(rating_filter) .bind(limit) .bind(offset) .fetch_all(pool) @@ -360,7 +439,11 @@ impl CatalogManager { pub async fn count_images(&self) -> Result { let pool = self.db.pool(); let count: i64 = sqlx::query_scalar( - "SELECT COUNT(*) FROM images WHERE is_archived = 0", + r#" + SELECT COUNT(*) + FROM images + WHERE is_archived = 0 + "#, ) .fetch_one(pool) .await?; @@ -375,4 +458,1224 @@ impl CatalogManager { pub fn get_preview_path(&self, image_id: i64) -> PathBuf { self.cache_dir.join(format!("preview_{}.jpg", image_id)) } + + /// Static method to import directory using a cloned pool (avoids holding mutex across await). + pub async fn import_directory_from_pool(pool: &SqlitePool, dir_path: &str) -> Result { + let dir = Path::new(dir_path); + + if !dir.exists() { + anyhow::bail!("Directory does not exist: {}", dir_path); + } + + let folder_id = Self::ensure_folder_static(dir_path, pool).await?; + + let mut imported = 0usize; + let mut queue = vec![dir.to_path_buf()]; + + while let Some(current_dir) = queue.pop() { + for entry in WalkDir::new(¤t_dir).into_iter().filter_map(|e| e.ok()) { + if entry.file_type().is_dir() { + if entry.file_name() != ".praetorian" { + queue.push(entry.path().to_path_buf()); + } + continue; + } + + let ext = entry + .path() + .extension() + .and_then(|e| e.to_str()) + .map(|s| s.to_lowercase()) + .unwrap_or_default(); + + if !SUPPORTED_EXTENSIONS.contains(&ext.as_str()) { + continue; + } + + let file_path = entry.path().to_string_lossy().to_string(); + + let exists: bool = sqlx::query_scalar( + r#"SELECT EXISTS( + SELECT 1 + FROM images + WHERE file_path = ? + )"#, + ) + .bind(&file_path) + .fetch_one(pool) + .await?; + + if exists { + continue; + } + + match Self::import_single_image_static(&file_path, folder_id, pool).await { + Ok(_) => imported += 1, + Err(e) => { + log::warn!("Failed to import {}: {}", file_path, e); + } + } + } + } + + Ok(imported) + } + + async fn import_single_image_static( + file_path: &str, + folder_id: i64, + pool: &SqlitePool, + ) -> Result { + let metadata = fs::metadata(file_path) + .context(format!("Cannot access file: {}", file_path))?; + + let file_name = Path::new(file_path) + .file_name() + .unwrap_or_default() + .to_string_lossy() + .to_string(); + + let file_extension = Path::new(file_path) + .extension() + .unwrap_or_default() + .to_string_lossy() + .to_string() + .to_lowercase(); + + let file_hash = Self::compute_file_hash(file_path)?; + + let exif = ExifParser::new() + .parse(file_path) + .unwrap_or_default(); + + let result = sqlx::query( + r#" + INSERT INTO images ( + folder_id, + file_path, + file_name, + file_extension, + file_size_bytes, + width, + height, + date_taken, + file_hash + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + "#, + ) + .bind(folder_id) + .bind(file_path) + .bind(file_name) + .bind(file_extension) + .bind(metadata.len() as i64) + .bind(exif.width.map(|w| w as i32)) + .bind(exif.height.map(|h| h as i32)) + .bind(exif.date_time_original.as_deref()) + .bind(file_hash) + .execute(pool) + .await?; + + let image_id = result.last_insert_rowid(); + + sqlx::query( + r#" + INSERT INTO exif_data ( + image_id, + camera_make, + camera_model, + lens_model, + iso, + aperture_f_number, + shutter_speed_num, + shutter_speed_den, + focal_length_mm, + gps_latitude, + gps_longitude, + gps_altitude + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "#, + ) + .bind(image_id) + .bind(exif.camera_make.as_deref()) + .bind(exif.camera_model.as_deref()) + .bind(exif.lens_model.as_deref()) + .bind(exif.iso.map(|i| i as i32)) + .bind(exif.aperture) + .bind(exif.shutter_num.map(|n| n as i32)) + .bind(exif.shutter_den.map(|d| d as i32)) + .bind(exif.focal_length) + .bind(exif.gps_latitude) + .bind(exif.gps_longitude) + .bind(exif.gps_altitude) + .execute(pool) + .await?; + + sqlx::query( + r#" + INSERT INTO processing_queue ( + image_id, + task_type, + priority + ) + VALUES (?, 'thumbnail', 10) + "#, + ) + .bind(image_id) + .execute(pool) + .await?; + + sqlx::query( + r#" + INSERT INTO processing_queue ( + image_id, + task_type, + priority + ) + VALUES (?, 'preview', 5) + "#, + ) + .bind(image_id) + .execute(pool) + .await?; + + Ok(image_id) + } + + async fn ensure_folder_static(path: &str, pool: &SqlitePool) -> Result { + let folder_name = Path::new(path) + .file_name() + .unwrap_or_default() + .to_string_lossy() + .to_string(); + + let existing: Option = sqlx::query_scalar( + r#" + SELECT id + FROM folders + WHERE path = ? + "#, + ) + .bind(path) + .fetch_optional(pool) + .await?; + + if let Some(id) = existing { + return Ok(id); + } + + let result = sqlx::query( + r#" + INSERT INTO folders ( + path, + name + ) + VALUES (?, ?) + "#, + ) + .bind(path) + .bind(folder_name) + .execute(pool) + .await?; + + Ok(result.last_insert_rowid()) + } + + /// Static method to list images using a cloned pool. + pub async fn list_images_from_pool( + pool: &SqlitePool, + offset: i64, + limit: i64, + rating_filter: Option, + ) -> Result> { + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT id, + folder_id, + file_path, + file_name, + file_extension, + file_size_bytes, + width, + height, + date_taken, + date_imported, + has_thumbnail, + has_preview, + rating, + is_favorite, + faces_indexed, + is_missing + FROM images + WHERE is_archived = 0 + AND (? IS NULL OR rating = ?) + ORDER BY date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(rating_filter) + .bind(rating_filter) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + /// Static method to count images using a cloned pool. + pub async fn count_images_from_pool(pool: &SqlitePool) -> Result { + let count: i64 = sqlx::query_scalar( + r#" + SELECT COUNT(*) + FROM images + WHERE is_archived = 0 + "#, + ) + .fetch_one(pool) + .await?; + Ok(count) + } + + /// Static method to list folders using a cloned pool. + pub async fn list_folders_from_pool(pool: &SqlitePool) -> Result> { + let folders = sqlx::query_as::<_, FolderRecord>( + r#" + SELECT id, + path, + name, + parent_id, + date_added, + is_watched + FROM folders + ORDER BY date_added DESC + "#, + ) + .fetch_all(pool) + .await?; + + Ok(folders) + } + + // ============================================ + // IMAGE DETAILS & EXIF + // ============================================ + + pub async fn get_image_details_from_pool(pool: &SqlitePool, image_id: i64) -> Result<(ImageRecord, Option)> { + let image: ImageRecord = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT id, + folder_id, + file_path, + file_name, + file_extension, + file_size_bytes, + width, + height, + date_taken, + date_imported, + has_thumbnail, + has_preview, + rating, + is_favorite, + faces_indexed, + is_missing + FROM images WHERE id = ? + "#, + ) + .bind(image_id) + .fetch_one(pool) + .await?; + + let exif: Option = sqlx::query_as::<_, ExifRecord>( + r#" + SELECT image_id, + camera_make, + camera_model, + lens_model, + iso, + aperture_f_number, + shutter_speed_num, + shutter_speed_den, + focal_length_mm, + gps_latitude, + gps_longitude, + gps_altitude + FROM exif_data + WHERE image_id = ? + "#, + ) + .bind(image_id) + .fetch_optional(pool) + .await?; + + Ok((image, exif)) + } + + // ============================================ + // RATING & FAVORITE + // ============================================ + + pub async fn update_rating_from_pool(pool: &SqlitePool, image_id: i64, rating: i32) -> Result<()> { + sqlx::query(r#" + UPDATE images + SET rating = ? + WHERE id = ? + "#) + .bind(rating) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn toggle_favorite_from_pool(pool: &SqlitePool, image_id: i64) -> Result { + let row = sqlx::query(r#" + UPDATE images + SET is_favorite = NOT is_favorite + WHERE id = ? + RETURNING is_favorite + "#, + ) + .bind(image_id) + .fetch_one(pool) + .await?; + let is_favorite: bool = row.try_get("is_favorite")?; + Ok(is_favorite) + } + + pub async fn set_favorite_from_pool(pool: &SqlitePool, image_id: i64, is_favorite: bool) -> Result<()> { + sqlx::query(r#" + UPDATE images + SET is_favorite = ? + WHERE id = ? + "#) + .bind(is_favorite) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + // ============================================ + // ARCHIVE & DELETE + // ============================================ + + pub async fn archive_image_from_pool(pool: &SqlitePool, image_id: i64, is_archived: bool) -> Result<()> { + sqlx::query(r#" + UPDATE images + SET is_archived = ? + WHERE id = ? + "#) + .bind(is_archived) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn delete_image_from_pool(pool: &SqlitePool, image_id: i64) -> Result<()> { + sqlx::query(r#" + DELETE FROM images + WHERE id = ? + "#) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn delete_images_from_pool(pool: &SqlitePool, image_ids: &[i64]) -> Result { + let mut total = 0usize; + for id in image_ids { + let _ = sqlx::query(r#" + DELETE FROM images + WHERE id = ? + "#) + .bind(id) + .execute(pool) + .await; + total += 1; + } + Ok(total) + } + + // ============================================ + // SEARCH & FILTER + // ============================================ + + pub async fn search_images_from_pool( + pool: &SqlitePool, + query: &str, + offset: i64, + limit: i64, + ) -> Result> { + let search = format!("%{}%", query); + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT id, + folder_id, + file_path, + file_name, + file_extension, + file_size_bytes, + width, + height, + date_taken, + date_imported, + has_thumbnail, + has_preview, + rating, + is_favorite, + faces_indexed, + is_missing + FROM images + WHERE is_archived = 0 + AND ( + file_name LIKE ? + OR file_path LIKE ? + ) + ORDER BY date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(&search) + .bind(&search) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn filter_by_camera_from_pool( + pool: &SqlitePool, + camera_model: &str, + offset: i64, + limit: i64, + ) -> Result> { + let search = format!("%{}%", camera_model); + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN exif_data e + ON e.image_id = i.id + WHERE i.is_archived = 0 + AND e.camera_model LIKE ? + ORDER BY i.date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(&search) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn filter_by_lens_from_pool( + pool: &SqlitePool, + lens_model: &str, + offset: i64, + limit: i64, + ) -> Result> { + let search = format!("%{}%", lens_model); + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported, + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN exif_data e + ON e.image_id = i.id + WHERE i.is_archived = 0 + AND e.lens_model LIKE ? + ORDER BY i.date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(&search) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn filter_by_person_from_pool( + pool: &SqlitePool, + person_id: i64, + offset: i64, + limit: i64, + ) -> Result> { + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT DISTINCT + i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported, + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN faces f + ON f.image_id = i.id + WHERE i.is_archived = 0 + AND f.person_id = ? + ORDER BY i.date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(person_id) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn filter_by_tag_from_pool( + pool: &SqlitePool, + tag_id: i64, + offset: i64, + limit: i64, + ) -> Result> { + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT DISTINCT + i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported, + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN image_tags it + ON it.image_id = i.id + WHERE i.is_archived = 0 + AND it.tag_id = ? + ORDER BY i.date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(tag_id) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn filter_by_album_from_pool( + pool: &SqlitePool, + album_id: i64, + offset: i64, + limit: i64, + ) -> Result> { + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT DISTINCT + i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported, + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN album_images ai + ON ai.image_id = i.id + WHERE i.is_archived = 0 + AND ai.album_id = ? + ORDER BY i.date_taken DESC + LIMIT ? OFFSET ? + "#, + ) + .bind(album_id) + .bind(limit) + .bind(offset) + .fetch_all(pool) + .await?; + + Ok(images) + } + + pub async fn count_search_results_from_pool( + pool: &SqlitePool, + query: &str, + ) -> Result { + let search = format!("%{}%", query); + let count: i64 = sqlx::query_scalar( + r#" + SELECT COUNT(*) + FROM images + WHERE is_archived = 0 + AND (file_name LIKE ? OR file_path LIKE ?) + "#, + ) + .bind(&search) + .bind(&search) + .fetch_one(pool) + .await?; + Ok(count) + } + + // ============================================ + // PEOPLE MANAGEMENT + // ============================================ + + pub async fn list_people_from_pool(pool: &SqlitePool) -> Result> { + let people = sqlx::query_as::<_, PersonRecord>( + r#" + SELECT p.id, + p.name, + p.created_at, + p.updated_at, + COUNT(f.id) AS face_count + FROM people p + LEFT JOIN faces f + ON f.person_id = p.id + GROUP BY p.id + ORDER BY p.name ASC + "#, + ) + .fetch_all(pool) + .await?; + Ok(people) + } + + pub async fn create_person_from_pool(pool: &SqlitePool, name: &str) -> Result { + let result = sqlx::query("INSERT INTO people (name) VALUES (?)") + .bind(name) + .execute(pool) + .await?; + Ok(result.last_insert_rowid()) + } + + pub async fn update_person_name_from_pool(pool: &SqlitePool, person_id: i64, name: &str) -> Result<()> { + sqlx::query( + r#" + UPDATE people + SET name = ?, + updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') + WHERE id = ? + "# + ) + .bind(name) + .bind(person_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn delete_person_from_pool(pool: &SqlitePool, person_id: i64) -> Result<()> { + sqlx::query( + r#" + DELETE + FROM people + WHERE id = ? + "# + ) + .bind(person_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn assign_face_to_person_from_pool( + pool: &SqlitePool, + face_id: i64, + person_id: i64, + ) -> Result<()> { + sqlx::query( + r#" + UPDATE faces + SET person_id = ? + WHERE id = ? + "# + ) + .bind(person_id) + .bind(face_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn unassign_face_from_person_from_pool(pool: &SqlitePool, face_id: i64) -> Result<()> { + sqlx::query( + r#" + UPDATE faces + SET person_id = NULL + WHERE id = ? + "# + ) + .bind(face_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn get_faces_for_image_from_pool(pool: &SqlitePool, image_id: i64) -> Result> { + let faces = sqlx::query_as::<_, FaceRecord>( + r#" + SELECT id, + image_id, + person_id, + bbox_x, + bbox_y, + bbox_width, + bbox_height, + confidence + FROM faces + WHERE image_id = ? + "#, + ) + .bind(image_id) + .fetch_all(pool) + .await?; + Ok(faces) + } + + pub async fn get_faces_for_person_from_pool(pool: &SqlitePool, person_id: i64) -> Result> { + let faces = sqlx::query_as::<_, FaceRecord>( + r#" + SELECT id, + image_id, + person_id, + bbox_x, + bbox_y, + bbox_width, + bbox_height, + confidence + FROM faces + WHERE person_id = ? + "#, + ) + .bind(person_id) + .fetch_all(pool) + .await?; + Ok(faces) + } + + pub async fn get_images_for_person_from_pool( + pool: &SqlitePool, + person_id: i64, + ) -> Result> { + let images = sqlx::query_as::<_, ImageRecord>( + r#" + SELECT DISTINCT i.id, + i.folder_id, + i.file_path, + i.file_name, + i.file_extension, + i.file_size_bytes, + i.width, + i.height, + i.date_taken, + i.date_imported, + i.has_thumbnail, + i.has_preview, + i.rating, + i.is_favorite, + i.faces_indexed, + i.is_missing + FROM images i + JOIN faces f + ON f.image_id = i.id + WHERE f.person_id = ? + ORDER BY i.date_taken DESC + "#, + ) + .bind(person_id) + .fetch_all(pool) + .await?; + Ok(images) + } + + // ============================================ + // TAG MANAGEMENT + // ============================================ + + pub async fn list_tags_from_pool(pool: &SqlitePool) -> Result> { + let tags = sqlx::query_as::<_, TagRecord>( + r#" + SELECT id, + name, + color + FROM tags + ORDER BY name ASC + "#, + ) + .fetch_all(pool) + .await?; + Ok(tags) + } + + pub async fn create_tag_from_pool(pool: &SqlitePool, name: &str, color: Option<&str>) -> Result { + let result = sqlx::query( + r#" + INSERT INTO tags ( + name, + color + ) VALUES (?, ?) + "#, + ) + .bind(name) + .bind(color) + .execute(pool) + .await?; + + Ok(result.last_insert_rowid()) + } + + pub async fn delete_tag_from_pool(pool: &SqlitePool, tag_id: i64) -> Result<()> { + sqlx::query( + r#" + DELETE FROM tags + WHERE id = ? + "#, + ) + .bind(tag_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn tag_image_from_pool(pool: &SqlitePool, image_id: i64, tag_id: i64) -> Result<()> { + sqlx::query( + r#" + INSERT OR IGNORE INTO image_tags ( + image_id, + tag_id + ) VALUES (?, ?) + "#, + ) + .bind(image_id) + .bind(tag_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn untag_image_from_pool(pool: &SqlitePool, image_id: i64, tag_id: i64) -> Result<()> { + sqlx::query( + r#" + DELETE + FROM image_tags + WHERE image_id = ? + AND tag_id = ? + "#, + ) + .bind(image_id) + .bind(tag_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn get_tags_for_image_from_pool(pool: &SqlitePool, image_id: i64) -> Result> { + let tags = sqlx::query_as::<_, TagRecord>( + r#" + SELECT t.id, + t.name, + t.color + FROM tags t + JOIN image_tags it + ON it.tag_id = t.id + WHERE it.image_id = ? + ORDER BY t.name ASC + "#, + ) + .bind(image_id) + .fetch_all(pool) + .await?; + Ok(tags) + } + + // ============================================ + // ALBUM MANAGEMENT + // ============================================ + + pub async fn list_albums_from_pool(pool: &SqlitePool) -> Result> { + let albums = sqlx::query_as::<_, AlbumRecord>(r#" + SELECT id, + name, + description, + created_at + FROM albums + ORDER BY created_at DESC + "#, + ) + .fetch_all(pool) + .await?; + Ok(albums) + } + + pub async fn create_album_from_pool( + pool: &SqlitePool, + name: &str, + description: Option<&str>, + ) -> Result { + let result = sqlx::query(r#" + INSERT INTO albums ( + name, + description + ) VALUES (?, ?) + "#, + ) + .bind(name) + .bind(description) + .execute(pool) + .await?; + Ok(result.last_insert_rowid()) + } + + pub async fn delete_album_from_pool(pool: &SqlitePool, album_id: i64) -> Result<()> { + sqlx::query(r#" + DELETE + FROM albums + WHERE id = ? + "#, + ) + .bind(album_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn add_image_to_album_from_pool(pool: &SqlitePool, album_id: i64, image_id: i64) -> Result<()> { + sqlx::query(r#" + INSERT OR IGNORE INTO album_images ( + album_id, + image_id + ) VALUES (?, ?) + "#, + ) + .bind(album_id) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn remove_image_from_album_from_pool(pool: &SqlitePool, album_id: i64, image_id: i64) -> Result<()> { + sqlx::query(r#" + DELETE + FROM album_images + WHERE album_id = ? + AND image_id = ? + "#, + ) + .bind(album_id) + .bind(image_id) + .execute(pool) + .await?; + Ok(()) + } + + pub async fn get_images_for_album_from_pool( + pool: &SqlitePool, + album_id: i64, + offset: i64, + limit: i64, + ) -> Result> { + Self::filter_by_album_from_pool(pool, album_id, offset, limit).await + } + + // ============================================ + // CATALOG STATS + // ============================================ + + pub async fn get_catalog_stats_from_pool(pool: &SqlitePool) -> Result { + let total_images: i64 = sqlx::query_scalar(r#" + SELECT COUNT(*) FROM images + "#, + ) + .fetch_one(pool) + .await?; + + let total_faces: i64 = sqlx::query_scalar(r#" + SELECT COUNT(*) FROM faces + "#, + ) + .fetch_one(pool) + .await?; + + let total_people: i64 = sqlx::query_scalar(r#" + SELECT COUNT(*) FROM people + "#, + ) + .fetch_one(pool) + .await?; + + let total_folders: i64 = sqlx::query_scalar(r#" + SELECT COUNT(*) FROM folders + "#, + ) + .fetch_one(pool) + .await?; + + let total_tags: i64 = sqlx::query_scalar(r#" + SELECT COUNT(*) + FROM tags + "#, + ) + .fetch_one(pool) + .await?; + + let unindexed_faces: i64 = sqlx::query_scalar( + r#" + SELECT COUNT(*) FROM images WHERE faces_indexed = 0 AND is_missing = 0 + "#, + ) + .fetch_one(pool) + .await?; + + let missing_files: i64 = sqlx::query_scalar( + r#" + SELECT COUNT(*) + FROM images + WHERE is_missing = 1 + "#, + ) + .fetch_one(pool) + .await?; + + Ok(CatalogStats { + total_images, + total_faces, + total_people, + total_folders, + total_tags, + unindexed_faces, + missing_files, + }) + } + + // ============================================ + // XMP EXPORT + // ============================================ + + pub async fn export_xmp_sidecars_from_pool( + pool: &SqlitePool, + image_ids: &[i64], + output_dir: &str, + ) -> Result { + if image_ids.is_empty() { + return Ok(0); + } + + let placeholders: Vec = (0..image_ids.len()).map(|i| format!("?{}", i + 1)).collect(); + let in_clause = placeholders.join(", "); + + let query = format!( + "SELECT file_path, rating, is_favorite FROM images WHERE id IN ({})", + in_clause + ); + + let mut query_builder = sqlx::query(&query); + for id in image_ids { + query_builder = query_builder.bind(id); + } + + let rows = query_builder.fetch_all(pool).await?; + let mut exported = 0; + + for row in rows { + let file_path: String = row.try_get("file_path")?; + let rating: i32 = row.try_get("rating")?; + let is_favorite: bool = row.try_get("is_favorite")?; + + let xmp_path = Path::new(&file_path).with_extension("xmp"); + let mut xmp = String::from("\n"); + xmp.push_str("\n"); + xmp.push_str(" \n"); + xmp.push_str(" \n"); + + if rating > 0 { + xmp.push_str(&format!(" {}\n", rating)); + } + if is_favorite { + xmp.push_str(" favorite\n"); + } + + xmp.push_str(" \n"); + xmp.push_str(" \n"); + xmp.push_str("\n"); + xmp.push_str(""); + + let out_path = Path::new(output_dir).join( + xmp_path.file_name().unwrap_or_default(), + ); + fs::write(&out_path, xmp) + .context(format!("Failed to write XMP: {}", out_path.display()))?; + exported += 1; + } + + Ok(exported) + } } diff --git a/src-tauri/src/db/schema.rs b/src-tauri/src/db/schema.rs index 0f1c6db..dd69b23 100644 --- a/src-tauri/src/db/schema.rs +++ b/src-tauri/src/db/schema.rs @@ -4,6 +4,3 @@ pub const SCHEMA_VERSION: &str = "1.0.0"; /// Catalog file extension. pub const CATALOG_EXTENSION: &str = "praetorian"; - -/// Full schema SQL is loaded from `schema.sql` by the migrations module. -/// This module exists to expose schema constants and version info. diff --git a/src-tauri/src/exif/parser.rs b/src-tauri/src/exif/parser.rs index b31a0f3..d332d5c 100644 --- a/src-tauri/src/exif/parser.rs +++ b/src-tauri/src/exif/parser.rs @@ -1,13 +1,12 @@ -use std::fs::File; -use std::io::Read; use anyhow::Result; +use image::ImageReader; /// Parsed EXIF metadata from an image file. #[derive(Debug, Clone, Default)] pub struct ExifData { // Dimensions - pub width: u32, - pub height: u32, + pub width: Option, + pub height: Option, // Camera pub camera_make: Option, @@ -54,18 +53,15 @@ impl ExifParser { let mut data = ExifData::default(); // Try to open with the image crate first - if let Ok(img) = image::io::Reader::open(path) { + if let Ok(img) = ImageReader::open(path) { if let Ok(img) = img.with_guessed_format() { - let metadata = img.header()?.exif(); - - if let Some(exif) = metadata { - data = self.parse_exif_bytes(exif)?; + if let Ok((w, h)) = img.into_dimensions() { + data.width = Some(w); + data.height = Some(h); } - // Get dimensions from header - let hdr = img.header()?; - data.width = hdr.width(); - data.height = hdr.height(); + // EXIF data is not available through ImageReader in image 0.25 + // We rely on the exif crate directly or exiftool fallback } } diff --git a/src-tauri/src/face/detector.rs b/src-tauri/src/face/detector.rs index 8d5e6b9..76d58aa 100644 --- a/src-tauri/src/face/detector.rs +++ b/src-tauri/src/face/detector.rs @@ -1,7 +1,10 @@ -use std::path::Path; -use std::sync::Arc; +use std::sync::Mutex; use anyhow::{Context, Result}; +use image::imageops::FilterType; +use image::{ImageBuffer, Rgb}; +use ort::session::Session; +use ort::value::TensorRef; use sqlx::SqlitePool; /// RetinaFace face detection engine using ONNX Runtime with GPU support. @@ -15,8 +18,8 @@ use sqlx::SqlitePool; pub struct FaceDetector { /// Path to the RetinaFace ONNX model file. model_path: String, - /// ONNX Runtime session (initialized lazily). - session: Option, + /// ONNX Runtime session (wrapped in Mutex for interior mutability). + session: Option>, } impl FaceDetector { @@ -30,28 +33,19 @@ impl FaceDetector { } /// Initializes the ONNX Runtime session with GPU support. - /// Tries providers in order: CUDA -> Vulkan -> CPU. + /// Tries providers in order: CUDA -> CPU. pub fn initialize(&mut self) -> Result<()> { - let mut providers = Vec::new(); - - // Try CUDA first (Nvidia GPUs) - providers.push( - ort::CUDAExecutionProvider::default() - .with_arm_math_memops(true) - .build(), - ); - - // Fallback to CPU - providers.push(ort::CPUExecutionProvider::default().build()); - - let session = ort::Session::builder() + let session = Session::builder() .map_err(|e| anyhow::anyhow!("Failed to create ONNX session builder: {}", e))? - .with_execution_providers(providers) + .with_execution_providers([ + ort::ep::CUDA::default().build(), + ort::ep::CPU::default().build(), + ]) .map_err(|e| anyhow::anyhow!("Failed to set execution providers: {}", e))? .commit_from_file(&self.model_path) .map_err(|e| anyhow::anyhow!("Failed to load ONNX model: {}", e))?; - self.session = Some(session); + self.session = Some(Mutex::new(session)); log::info!("FaceDetector initialized with model: {}", self.model_path); Ok(()) @@ -69,18 +63,17 @@ impl FaceDetector { let img = image::open(image_path) .context(format!("Failed to open image: {}", image_path))?; - let (img_width, img_height) = (img.width(), img.height()); + let img_width = img.width(); // RetinaFace typically expects input at specific anchor scales. // We resize while maintaining aspect ratio and pad to model input size. let target_size = 640u32; let resized = self.prepare_input(&img, target_size); - let input_len = resized.width() * resized.height() * 3; let input_data: Vec = resized .pixels() .flat_map(|p| { - // BGR format, normalized to [0, 1], with mean subtraction + // BGR format, with mean subtraction // RetinaFace uses mean=[122.6789, 116.6687, 104.0069] vec![ (p[2] as f32 - 122.6789f32), @@ -90,22 +83,19 @@ impl FaceDetector { }) .collect(); - // Create input tensor - let input_shape = vec![1, 3, resized.height() as i64, resized.width() as i64]; - let input_tensor = ort::Tensor::::from_vec( - ort::Environment::default(), - input_data, - input_shape, - ) - .map_err(|e| anyhow::anyhow!("Failed to create input tensor: {}", e))?; + // Create input tensor using ort 2.0 API + let input_shape = vec![1, 3, resized.height() as usize, resized.width() as usize]; + let input_tensor = TensorRef::from_array_view((input_shape, input_data.as_slice())) + .map_err(|e| anyhow::anyhow!("Failed to create input tensor: {}", e))?; - // Run inference - let outputs = session - .run(ort::Inputs::one(input_tensor)) + // Run inference using ort 2.0 inputs! macro + let mut sess = session.lock().map_err(|e| anyhow::anyhow!("Mutex poisoned: {}", e))?; + let outputs = sess + .run(ort::inputs![input_tensor]) .map_err(|e| anyhow::anyhow!("ONNX inference failed: {}", e))?; // Parse outputs: RetinaFace outputs [loc, conf, landmarks] - let detections = self.parse_outputs(&outputs, img_width, img_height); + let detections = self.parse_outputs(&outputs, img_width, img.height()); Ok(detections) } @@ -126,25 +116,25 @@ impl FaceDetector { } /// Prepares an image for RetinaFace input: resize, pad, convert to BGR. - fn prepare_input(&self, img: &image::DynamicImage, target_size: u32) -> image::RgbImage { + fn prepare_input(&self, img: &image::DynamicImage, target_size: u32) -> ImageBuffer, Vec> { let (w, h) = (img.width(), img.height()); let scale = target_size as f64 / w.max(h) as f64; let new_w = (w as f64 * scale).round() as u32; let new_h = (h as f64 * scale).round() as u32; - let resized = img.resize(new_w, new_h, image::ImageFilter::Triangle); + let resized = img.resize(new_w, new_h, FilterType::Triangle); + let rgb = resized.into_rgb8(); // Pad to square - let padded = image::imageops::map( - &image::RgbImage::new(target_size, target_size, image::Rgb([0u8, 0, 0])), - |x, y, rgb| { - if x < new_w && y < new_h { - *rgb = resized.get_pixel(x, y); - } - *rgb - }, - ); + let mut padded = ImageBuffer::new(target_size, target_size); + + for y in 0..new_h { + for x in 0..new_w { + let pixel = rgb.get_pixel(x, y); + padded.put_pixel(x, y, *pixel); + } + } padded } @@ -152,23 +142,23 @@ impl FaceDetector { /// Parses ONNX outputs into face detections. fn parse_outputs( &self, - outputs: &ort::Outputs, - img_width: u32, - img_height: u32, + outputs: &ort::session::SessionOutputs, + _img_width: u32, + _img_height: u32, ) -> Vec { - let mut detections = Vec::new(); + let detections = Vec::new(); // RetinaFace outputs: // - output[0]: bounding box predictions (N, 4) // - output[1]: confidence scores (N, 2) [background, face] // - output[2..]: landmark predictions - // Simplified parsing - actual implementation depends on specific model output format - for output in outputs.iter() { - if let Some(data) = output.try_extract_tensor::() { - let view = data.unwrap(); + // Parse outputs using ort 2.0 API + for (_name, output) in outputs.iter() { + if let Ok((shape, data)) = output.try_extract_tensor::() { // Parse bounding boxes and confidence scores // This is a simplified version; actual parsing depends on model architecture + let _ = (shape, data); } } @@ -200,7 +190,7 @@ pub async fn store_faces( detections: &[FaceDetection], ) -> Result<()> { for det in detections { - sqlx::query!( + sqlx::query( r#" INSERT INTO faces ( image_id, @@ -212,22 +202,22 @@ pub async fn store_faces( ) VALUES (?, ?, ?, ?, ?, ?) "#, - image_id, - det.bbox_x, - det.bbox_y, - det.bbox_width, - det.bbox_height, - det.confidence, ) + .bind(image_id) + .bind(det.bbox_x) + .bind(det.bbox_y) + .bind(det.bbox_width) + .bind(det.bbox_height) + .bind(det.confidence) .execute(pool) .await?; } // Mark image as face-indexed - sqlx::query!( + sqlx::query( "UPDATE images SET faces_indexed = 1 WHERE id = ?", - image_id, ) + .bind(image_id) .execute(pool) .await?; @@ -236,7 +226,7 @@ pub async fn store_faces( /// Triggers a full face re-index of all images that haven't been indexed yet. pub async fn rebuild_face_index(pool: &SqlitePool, detector: &FaceDetector) -> Result<()> { - let unindexed: Vec = sqlx::query_scalar!( + let unindexed: Vec = sqlx::query_scalar::<_, String>( r#" SELECT file_path FROM images @@ -245,10 +235,7 @@ pub async fn rebuild_face_index(pool: &SqlitePool, detector: &FaceDetector) -> R "# ) .fetch_all(pool) - .await? - .into_iter() - .map(|p| p.unwrap_or_default()) - .collect(); + .await?; log::info!("Rebuilding face index for {} images", unindexed.len()); @@ -256,10 +243,10 @@ pub async fn rebuild_face_index(pool: &SqlitePool, detector: &FaceDetector) -> R match detector.detect_faces(path).await { Ok(detections) => { if !detections.is_empty() { - let image_id: i64 = sqlx::query_scalar!( + let image_id: i64 = sqlx::query_scalar( "SELECT id FROM images WHERE file_path = ?", - path ) + .bind(path) .fetch_one(pool) .await?; diff --git a/src-tauri/src/face/mod.rs b/src-tauri/src/face/mod.rs index 4c98ab1..eaf441e 100644 --- a/src-tauri/src/face/mod.rs +++ b/src-tauri/src/face/mod.rs @@ -1 +1,2 @@ +#[cfg(feature = "face-detection")] pub mod detector; diff --git a/src-tauri/src/image/pipeline.rs b/src-tauri/src/image/pipeline.rs index d938da1..3811b2a 100644 --- a/src-tauri/src/image/pipeline.rs +++ b/src-tauri/src/image/pipeline.rs @@ -1,5 +1,4 @@ use std::path::{Path, PathBuf}; -use std::sync::Arc; use tokio::sync::mpsc; use tokio::task::JoinHandle; @@ -20,13 +19,17 @@ const THUMB_QUALITY: u8 = 75; const PREVIEW_QUALITY: u8 = 85; /// Maximum concurrent image processing tasks. -const MAX_CONCURRENT_TASKS: usize = 8; +const MAX_CONCURRENT_TASKS: usize = 4; + +/// How often the worker polls the DB queue when the channel is empty (ms). +const DB_POLL_INTERVAL_MS: u64 = 200; /// Represents a queued image processing job. #[derive(Debug, Clone)] pub struct ProcessingJob { + pub queue_id: i64, pub image_id: i64, - pub source_path: String, + pub file_path: String, pub job_type: JobType, } @@ -36,8 +39,12 @@ pub enum JobType { Preview, } -/// The image processing pipeline. Runs as a background worker pool -/// driven by a tokio task and a channel-based job queue. +/// The image processing pipeline. +/// +/// Runs a background worker that drains jobs from a tokio channel and the +/// persistent `processing_queue` SQLite table. Jobs submitted via `submit` +/// go through the channel for immediate processing. When the channel drains, +/// the worker polls the DB for any persisted jobs (crash-recovery / backlog). pub struct ImagePipeline { cache_dir: PathBuf, sender: mpsc::Sender, @@ -57,9 +64,8 @@ impl ImagePipeline { } /// Starts the background processing worker. - /// Spawns a tokio task that drains the job queue and processes images - /// using libvips without blocking the Tauri UI thread. - pub fn start(&mut self, pool: Arc) -> &mut Self { + /// Spawns a tokio task that processes jobs without blocking the Tauri UI thread. + pub fn start(&mut self, pool: SqlitePool) { let receiver = self .receiver .take() @@ -71,23 +77,24 @@ impl ImagePipeline { }); self.worker_handle = Some(handle); - self + log::info!("ImagePipeline worker started"); } - /// Submits a job to the processing queue. + /// Submits a job to the processing channel for immediate pickup by the worker. pub async fn submit(&self, job: ProcessingJob) -> Result<()> { self.sender .send(job) .await - .map_err(|e| anyhow::anyhow!(e)) + .map_err(|e| anyhow::anyhow!("Pipeline channel closed: {}", e)) } /// Submits thumbnail generation for a batch of images. pub async fn queue_thumbnails(&self, images: &[(i64, String)]) -> Result<()> { for (image_id, source_path) in images { self.submit(ProcessingJob { + queue_id: 0, image_id: *image_id, - source_path: source_path.clone(), + file_path: source_path.clone(), job_type: JobType::Thumbnail, }) .await?; @@ -99,8 +106,9 @@ impl ImagePipeline { pub async fn queue_previews(&self, images: &[(i64, String)]) -> Result<()> { for (image_id, source_path) in images { self.submit(ProcessingJob { + queue_id: 0, image_id: *image_id, - source_path: source_path.clone(), + file_path: source_path.clone(), job_type: JobType::Preview, }) .await?; @@ -108,96 +116,232 @@ impl ImagePipeline { Ok(()) } - /// Core worker loop: processes jobs from the channel using libvips. - /// Uses a semaphore-like pattern to limit concurrency. + /// Core worker loop: processes jobs from the channel, then polls the DB queue. async fn worker_loop( mut receiver: mpsc::Receiver, cache_dir: PathBuf, - pool: Arc, + pool: SqlitePool, ) { - let mut active_tasks: Vec> = Vec::new(); + log::info!("Worker loop started, cache_dir={}", cache_dir.display()); + + loop { + // Phase 1: drain channel jobs with timeout + match tokio::time::timeout( + tokio::time::Duration::from_millis(DB_POLL_INTERVAL_MS), + receiver.recv(), + ) + .await { + Ok(Some(job)) => { + Self::process_job(job, &cache_dir, &pool).await; + continue; + } + Ok(None) => { + // Channel closed + break; + } + Err(_) => { + // Timeout — poll DB for persisted jobs + } + } - while let Some(job) = receiver.recv().await { - // Limit concurrent tasks - while active_tasks.len() >= MAX_CONCURRENT_TASKS { - active_tasks.retain(|t| !t.is_finished()); - tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; + // Phase 2: poll DB queue for pending jobs + if let Err(e) = Self::drain_db_queue(&cache_dir, &pool).await { + log::error!("Error draining DB queue: {}", e); } + } - let source = job.source_path.clone(); - let image_id = job.image_id; - let job_type = job.job_type.clone(); - let out_dir = cache_dir.clone(); - let db_pool = pool.clone(); - - let task = tokio::spawn(async move { - match job_type { - JobType::Thumbnail => { - if let Err(e) = - Self::generate_thumbnail(&source, image_id, &out_dir, &db_pool).await - { - log::error!( - "Failed to generate thumbnail for image {}: {}", - image_id, - e - ); - } - } - JobType::Preview => { - if let Err(e) = - Self::generate_preview(&source, image_id, &out_dir, &db_pool).await - { - log::error!( - "Failed to generate preview for image {}: {}", - image_id, - e - ); - } - } + log::info!("Worker loop exited (channel closed)"); + } + + /// Polls the `processing_queue` table for pending jobs and processes them. + async fn drain_db_queue(cache_dir: &Path, pool: &SqlitePool) -> Result<()> { + let pending: Vec<(i64, i64, String, String)> = sqlx::query_as( + r#" + SELECT pq.id, + pq.image_id, + i.file_path, + pq.task_type + FROM processing_queue pq + JOIN images i + ON i.id = pq.image_id + WHERE pq.status = 'pending' + ORDER BY pq.priority DESC + LIMIT ? + "#, + ) + .bind(MAX_CONCURRENT_TASKS as i64) + .fetch_all(pool) + .await?; + + if pending.is_empty() { + return Ok(()); + } + + let mut handles = Vec::new(); + + for (queue_id, image_id, file_path, task_type) in pending { + let job_type = match task_type.as_str() { + "thumbnail" => JobType::Thumbnail, + "preview" => JobType::Preview, + _ => { + log::warn!("Unknown task_type '{}', skipping", task_type); + continue; } + }; + + let job = ProcessingJob { + queue_id, + image_id, + file_path, + job_type, + }; + + let cd = cache_dir.to_path_buf(); + let p = pool.clone(); + + let handle = tokio::spawn(async move { + Self::process_job(job, &cd, &p).await; }); + handles.push(handle); + } - active_tasks.push(task); + // Wait for all spawned jobs to complete + for handle in handles { + let _ = handle.await; } + + Ok(()) } - /// Generates a tiny thumbnail using libvips. - async fn generate_thumbnail( - source_path: &str, - image_id: i64, - cache_dir: &Path, - pool: &SqlitePool, - ) -> Result<()> { - let output_path = cache_dir.join(format!("thumb_{}.jpg", image_id)); + /// Dispatches a single job to the appropriate generation function. + async fn process_job(job: ProcessingJob, cache_dir: &Path, pool: &SqlitePool) { + let queue_id = job.queue_id; + let image_id = job.image_id; + let source = job.file_path.clone(); - let result = Self::resize_and_save( - source_path, - &output_path, - THUMB_MAX_DIM, - THUMB_QUALITY, + log::debug!( + "Processing job: image_id={}, type={:?}", + image_id, + job.job_type ); + // Mark as in-progress if from DB queue + if queue_id > 0 { + if let Err(e) = sqlx::query( + r#" + UPDATE processing_queue + SET status = 'in_progress', + started_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') + WHERE id = ? + "#, + ) + .bind(queue_id) + .execute(pool) + .await + { + log::error!("Failed to mark job {} as in_progress: {}", queue_id, e); + } + } + + let result = match job.job_type { + JobType::Thumbnail => { + Self::generate_thumbnail(&source, image_id, cache_dir, pool).await + } + JobType::Preview => { + Self::generate_preview(&source, image_id, cache_dir, pool).await + } + }; + + // Update DB queue status + if queue_id > 0 { + match &result { + Ok(_) => { + if let Err(e) = sqlx::query( + r#" + UPDATE processing_queue + SET status = 'completed', + completed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') + WHERE id = ? + "#, + ) + .bind(queue_id) + .execute(pool) + .await + { + log::error!("Failed to mark job {} as completed: {}", queue_id, e); + } + } + Err(e) => { + let err_msg = e.to_string(); + if let Err(db_e) = sqlx::query( + r#" + UPDATE processing_queue + SET status = 'failed', + error_message = ?, + completed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') + WHERE id = ? + "#, + ) + .bind(&err_msg) + .bind(queue_id) + .execute(pool) + .await + { + log::error!("Failed to mark job {} as failed: {}", queue_id, db_e); + } + } + } + } + match result { Ok(_) => { - sqlx::query!( - "UPDATE images SET has_thumbnail = 1, thumbnail_hash = ? WHERE id = ?", - output_path.file_name().unwrap().to_string_lossy(), - image_id, - ) - .execute(pool) - .await?; - log::debug!("Generated thumbnail for image {}", image_id); + log::debug!( + "Completed {:?} for image {}", + job.job_type, + image_id + ); } Err(e) => { - log::error!("vips thumbnail error for {}: {}", source_path, e); - return Err(e); + log::error!( + "Failed {:?} for image {} ({}) : {}", + job.job_type, + image_id, + source, + e + ); } } + } + /// Generates a tiny thumbnail (160px max, 75% quality). + async fn generate_thumbnail( + source_path: &str, + image_id: i64, + cache_dir: &Path, + pool: &SqlitePool, + ) -> Result<()> { + let output_path = cache_dir.join(format!("thumb_{}.jpg", image_id)); + + Self::resize_and_save(source_path, &output_path, THUMB_MAX_DIM, THUMB_QUALITY)?; + + sqlx::query( + r#" + UPDATE images + SET has_thumbnail = 1, + thumbnail_hash = ? + WHERE id = ? + "#, + ) + .bind(output_path.file_name().unwrap().to_string_lossy().to_string()) + .bind(image_id) + .execute(pool) + .await?; + + log::debug!("Generated thumbnail for image {}", image_id); Ok(()) } - /// Generates a smart preview (2048px max) using libvips. + /// Generates a smart preview (2048px max, 85% quality). async fn generate_preview( source_path: &str, image_id: i64, @@ -206,78 +350,132 @@ impl ImagePipeline { ) -> Result<()> { let output_path = cache_dir.join(format!("preview_{}.jpg", image_id)); - let result = Self::resize_and_save( - source_path, - &output_path, - PREVIEW_MAX_DIM, - PREVIEW_QUALITY, - ); + Self::resize_and_save(source_path, &output_path, PREVIEW_MAX_DIM, PREVIEW_QUALITY)?; + + sqlx::query( + r#" + UPDATE images + SET has_preview = 1, + preview_hash = ? + WHERE id = ? + "#, + ) + .bind(output_path.file_name().unwrap().to_string_lossy().to_string()) + .bind(image_id) + .execute(pool) + .await?; + + log::debug!("Generated preview for image {}", image_id); + Ok(()) + } - match result { - Ok(_) => { - sqlx::query!( - r#" - UPDATE images - SET has_preview = 1, - preview_hash = ? - WHERE id = ? - "#, - output_path.file_name().unwrap().to_string_lossy(), - image_id, - ) - .execute(pool) - .await?; - log::debug!("Generated preview for image {}", image_id); - } - Err(e) => { - log::error!("vips preview error for {}: {}", source_path, e); - return Err(e); - } + /// Resizes an image to the given max dimension and saves as JPEG. + /// Uses libvips when the `vips` feature is enabled, otherwise falls back to `image`. + fn resize_and_save( + input: &str, + output: &Path, + max_dim: u32, + quality: u8, + ) -> Result<()> { + #[cfg(feature = "vips")] + { + return Self::resize_with_vips(input, output, max_dim, quality); + } + + #[cfg(not(feature = "vips"))] + { + return Self::resize_with_image(input, output, max_dim, quality); + } + } + + /// Resize using libvips (fast, supports RAW via built-in loaders). + #[cfg(feature = "vips")] + fn resize_with_vips( + input: &str, + output: &Path, + max_dim: u32, + quality: u8, + ) -> Result<()> { + use std::ffi::CString; + use std::os::raw::c_char; + use std::ptr::null; + + let output_str = output + .to_str() + .ok_or_else(|| anyhow::anyhow!("Invalid output path"))?; + let out_c = CString::new(output_str)?; + + // Load image from file + let img = vips::VipsImage::from_file(input)?; + + // Create thumbnail (downscale to fit within max_dim x max_dim) + let thumb = img.thumbnail( + max_dim, + max_dim, + vips::VipsSize::VIPS_SIZE_DOWN, + )?; + + // Write as JPEG with quality setting + let ret = unsafe { + vips_sys::vips_jpegsave( + thumb.c, + out_c.as_ptr(), + c"Q".as_ptr(), + quality as i32, + null() as *const c_char, + ) + }; + + if ret != 0 { + anyhow::bail!( + "vips_jpegsave failed: {}", + vips::take_vips_error() + .unwrap_or_else(|| "Unknown vips error".to_string()) + ); } Ok(()) } - /// Uses libvips to resize an image to the given max dimension and save as JPEG. - /// This is the core vips operation that handles RAW, TIFF, and standard formats. - fn resize_and_save( + /// Resize using the `image` crate (slower, no RAW support). + #[cfg(not(feature = "vips"))] + fn resize_with_image( input: &str, output: &Path, max_dim: u32, quality: u8, ) -> Result<()> { - let img = vips::image::load(input)?; + use image::codecs::jpeg::JpegEncoder; + use image::{ExtendedColorType, GenericImageView, ImageEncoder, ImageReader}; + + let img = ImageReader::open(input)?.decode()?; + let (w, h) = img.dimensions(); - let (width, height) = (img.width(), img.height()); - let scale = if width > height { - max_dim as f64 / width as f64 + let scale = if w > h { + max_dim as f64 / w as f64 } else { - max_dim as f64 / height as f64 + max_dim as f64 / h as f64 }; - if scale >= 1.0 { - // Image is already smaller than target; just convert to JPEG - img.write_jpeg( - output.to_str().unwrap(), - vips::image::JpegOptions { - Q: quality as i32, - ..Default::default() - }, - )?; + let rgb8 = if scale >= 1.0 { + img.into_rgb8() } else { - let resized = img.resize(vips::image::ResizeOptions { - scale_factor: Some(scale), - ..Default::default() - })?; - - resized.write_jpeg( - output.to_str().unwrap(), - vips::image::JpegOptions { - Q: quality as i32, - ..Default::default() - }, - )?; - } + let new_w = (w as f64 * scale).max(1.0) as u32; + let new_h = (h as f64 * scale).max(1.0) as u32; + img.resize(new_w, new_h, image::imageops::FilterType::Lanczos3) + .into_rgb8() + }; + + let (out_w, out_h) = rgb8.dimensions(); + let mut buf = Vec::new(); + let encoder = JpegEncoder::new_with_quality(&mut buf, quality); + encoder.write_image( + rgb8.as_raw(), + out_w, + out_h, + ExtendedColorType::Rgb8, + )?; + std::fs::write(output, buf)?; Ok(()) } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 983fc72..058bcc8 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2,22 +2,28 @@ mod db; mod catalog; mod image; mod exif; +#[cfg(feature = "face-detection")] mod face; mod python; -use std::path::PathBuf; -use std::sync::Mutex; -use std::sync::Arc; - use anyhow::Result; -use tauri::{Emitter, Manager, State}; -use catalog::manager::CatalogManager; +use tokio::sync::Mutex; +use tauri::{Manager, State}; +use sqlx::SqlitePool; +use catalog::manager::{CatalogManager, FaceRecord, PersonRecord, TagRecord, AlbumRecord, CatalogStats}; /// App-level state shared across Tauri commands. pub struct AppState { pub catalog: Mutex>, } +/// Extract the SQLite pool from app state, or return an error if no catalog is open. +async fn get_pool(state: State<'_, AppState>) -> Result { + let guard = state.catalog.lock().await; + let catalog = guard.as_ref().ok_or_else(|| "No catalog open".to_string())?; + Ok(catalog.db.pool().clone()) +} + #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) @@ -30,7 +36,7 @@ async fn open_catalog(path: String, state: State<'_, AppState>) -> Result) -> Result, ) -> Result { - let guard = state.catalog.lock().unwrap(); - let catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; + let pool = get_pool(state).await?; - let imported = catalog - .import_directory(&dir_path) + let imported = CatalogManager::import_directory_from_pool(&pool, &dir_path) .await .map_err(|e| e.to_string())?; - drop(guard); - - // Emit event to frontend - // app.emit("import:complete", imported).ok(); - Ok(imported) } @@ -79,13 +76,9 @@ async fn list_images( rating_filter: Option, state: State<'_, AppState>, ) -> Result, String> { - let guard = state.catalog.lock().unwrap(); - let catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; + let pool = get_pool(state).await?; - let images = catalog - .list_images(offset, limit, rating_filter) + let images = CatalogManager::list_images_from_pool(&pool, offset, limit, rating_filter) .await .map_err(|e| e.to_string())?; @@ -95,12 +88,11 @@ async fn list_images( /// Returns the total number of images in the catalog. #[tauri::command] async fn count_images(state: State<'_, AppState>) -> Result { - let guard = state.catalog.lock().unwrap(); - let catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; + let pool = get_pool(state).await?; - let count = catalog.count_images().await.map_err(|e| e.to_string())?; + let count = CatalogManager::count_images_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; Ok(count) } @@ -110,19 +102,16 @@ async fn list_folders( state: State<'_, AppState>, ) -> Result, String> { let pool = { - let guard = state.catalog.lock().unwrap(); + let guard = state.catalog.lock().await; let catalog = guard .as_ref() .ok_or_else(|| "No catalog open".to_string())?; catalog.db.pool().clone() }; - let folders = sqlx::query_as::<_, catalog::manager::FolderRecord>( - "SELECT id, path, name, parent_id, date_added, is_watched FROM folders ORDER BY date_added DESC", - ) - .fetch_all(&pool) - .await - .map_err(|e| e.to_string())?; + let folders = CatalogManager::list_folders_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; Ok(folders) } @@ -133,13 +122,15 @@ async fn get_thumbnail_path( image_id: i64, state: State<'_, AppState>, ) -> Result { - let guard = state.catalog.lock().unwrap(); - let catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; + let path = { + let guard = state.catalog.lock().await; + let catalog = guard + .as_ref() + .ok_or_else(|| "No catalog open".to_string())?; - let path = catalog.get_thumbnail_path(image_id); - Ok(path.to_string_lossy().to_string()) + catalog.get_thumbnail_path(image_id).to_string_lossy().to_string() + }; + Ok(path) } /// Returns the filesystem path to a smart preview for a given image. @@ -148,26 +139,42 @@ async fn get_preview_path( image_id: i64, state: State<'_, AppState>, ) -> Result { - let guard = state.catalog.lock().unwrap(); - let catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; + let path = { + let guard = state.catalog.lock().await; + let catalog = guard + .as_ref() + .ok_or_else(|| "No catalog open".to_string())?; - let path = catalog.get_preview_path(image_id); - Ok(path.to_string_lossy().to_string()) + catalog.get_preview_path(image_id).to_string_lossy().to_string() + }; + Ok(path) } /// Starts the background face detection index for all unindexed images. #[tauri::command] async fn start_face_index(state: State<'_, AppState>) -> Result<(), String> { - // This would spawn a background tokio task that iterates over unindexed images, - // runs the RetinaFace detector, and stores results in the DB. - let guard = state.catalog.lock().unwrap(); - let _catalog = guard - .as_ref() - .ok_or_else(|| "No catalog open".to_string())?; - - // Placeholder: actual implementation spawns face::detector::rebuild_face_index + let pool = { + let guard = state.catalog.lock().await; + let catalog = guard + .as_ref() + .ok_or_else(|| "No catalog open".to_string())?; + catalog.db.pool().clone() + }; + + #[cfg(feature = "face-detection")] + { + let mut detector = face::detector::FaceDetector::new("retinaface.onnx"); + if let Err(e) = detector.initialize() { + log::warn!("FaceDetector initialization failed, falling back to CPU: {}", e); + } + face::detector::rebuild_face_index(&pool, &detector).await.map_err(|e| e.to_string())?; + } + + #[cfg(not(feature = "face-detection"))] + { + let _ = pool; + } + Ok(()) } @@ -177,7 +184,7 @@ async fn upscale_image( image_path: String, output_dir: String, scale: u32, - state: State<'_, AppState>, + _state: State<'_, AppState>, ) -> Result { let bridge = python::bridge::PythonBridge::with_defaults(); @@ -189,9 +196,571 @@ async fn upscale_image( Ok(result.output_path) } +/// Gets detailed info (including EXIF) for a single image. +#[tauri::command] +async fn get_image_details( + image_id: i64, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let (image, exif) = CatalogManager::get_image_details_from_pool(&pool, image_id) + .await + .map_err(|e| e.to_string())?; + + let mut obj = serde_json::to_value(&image).map_err(|e| e.to_string())?; + if let Some(exif_data) = exif { + if let Some(obj_obj) = obj.as_object_mut() { + obj_obj.insert("exif".to_string(), serde_json::to_value(&exif_data).unwrap()); + } + } + Ok(obj) +} + +/// Updates the rating for an image. +#[tauri::command] +async fn update_rating( + image_id: i64, + rating: i32, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::update_rating_from_pool(&pool, image_id, rating) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Toggles the favorite status of an image. +#[tauri::command] +async fn toggle_favorite( + image_id: i64, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let is_favorite = CatalogManager::toggle_favorite_from_pool(&pool, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(is_favorite) +} + +/// Sets the favorite status of an image explicitly. +#[tauri::command] +async fn set_favorite( + image_id: i64, + is_favorite: bool, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::set_favorite_from_pool(&pool, image_id, is_favorite) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Archives or unarchives an image. +#[tauri::command] +async fn archive_image( + image_id: i64, + is_archived: bool, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::archive_image_from_pool(&pool, image_id, is_archived) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Deletes an image from the catalog. +#[tauri::command] +async fn delete_image( + image_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::delete_image_from_pool(&pool, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Deletes multiple images from the catalog. +#[tauri::command] +async fn delete_images( + image_ids: Vec, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let deleted = CatalogManager::delete_images_from_pool(&pool, &image_ids) + .await + .map_err(|e| e.to_string())?; + Ok(deleted) +} + +/// Searches images by file name or path. +#[tauri::command] +async fn search_images( + query: String, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::search_images_from_pool(&pool, &query, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +/// Counts search results for a query. +#[tauri::command] +async fn count_search_results( + query: String, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let count = CatalogManager::count_search_results_from_pool(&pool, &query) + .await + .map_err(|e| e.to_string())?; + Ok(count) +} + +/// Filters images by camera model. +#[tauri::command] +async fn filter_by_camera( + camera_model: String, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::filter_by_camera_from_pool(&pool, &camera_model, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +/// Filters images by lens model. +#[tauri::command] +async fn filter_by_lens( + lens_model: String, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::filter_by_lens_from_pool(&pool, &lens_model, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +/// Filters images by person (face recognition). +#[tauri::command] +async fn filter_by_person( + person_id: i64, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::filter_by_person_from_pool(&pool, person_id, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +/// Filters images by tag. +#[tauri::command] +async fn filter_by_tag( + tag_id: i64, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::filter_by_tag_from_pool(&pool, tag_id, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +/// Filters images by album. +#[tauri::command] +async fn filter_by_album( + album_id: i64, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::filter_by_album_from_pool(&pool, album_id, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +// ============================================ +// PEOPLE MANAGEMENT +// ============================================ + +/// Lists all recognized people. +#[tauri::command] +async fn list_people(state: State<'_, AppState>) -> Result, String> { + let pool = get_pool(state).await?; + + let people = CatalogManager::list_people_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; + Ok(people) +} + +/// Creates a new person entry. +#[tauri::command] +async fn create_person( + name: String, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let id = CatalogManager::create_person_from_pool(&pool, &name) + .await + .map_err(|e| e.to_string())?; + Ok(id) +} + +/// Updates a person's name. +#[tauri::command] +async fn update_person_name( + person_id: i64, + name: String, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::update_person_name_from_pool(&pool, person_id, &name) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Deletes a person entry. +#[tauri::command] +async fn delete_person( + person_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::delete_person_from_pool(&pool, person_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Assigns a detected face to a person. +#[tauri::command] +async fn assign_face_to_person( + face_id: i64, + person_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::assign_face_to_person_from_pool(&pool, face_id, person_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Removes a face from its person assignment. +#[tauri::command] +async fn unassign_face_from_person( + face_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::unassign_face_from_person_from_pool(&pool, face_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Gets all detected faces for a specific image. +#[tauri::command] +async fn get_faces_for_image( + image_id: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let faces = CatalogManager::get_faces_for_image_from_pool(&pool, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(faces) +} + +/// Gets all faces assigned to a person. +#[tauri::command] +async fn get_faces_for_person( + person_id: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let faces = CatalogManager::get_faces_for_person_from_pool(&pool, person_id) + .await + .map_err(|e| e.to_string())?; + Ok(faces) +} + +/// Gets all images for a person. +#[tauri::command] +async fn get_images_for_person( + person_id: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::get_images_for_person_from_pool(&pool, person_id) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +// ============================================ +// TAG MANAGEMENT +// ============================================ + +/// Lists all tags. +#[tauri::command] +async fn list_tags(state: State<'_, AppState>) -> Result, String> { + let pool = get_pool(state).await?; + + let tags = CatalogManager::list_tags_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; + Ok(tags) +} + +/// Creates a new tag. +#[tauri::command] +async fn create_tag( + name: String, + color: Option, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let id = CatalogManager::create_tag_from_pool(&pool, &name, color.as_deref()) + .await + .map_err(|e| e.to_string())?; + Ok(id) +} + +/// Deletes a tag. +#[tauri::command] +async fn delete_tag( + tag_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::delete_tag_from_pool(&pool, tag_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Tags an image. +#[tauri::command] +async fn tag_image( + image_id: i64, + tag_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::tag_image_from_pool(&pool, image_id, tag_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Removes a tag from an image. +#[tauri::command] +async fn untag_image( + image_id: i64, + tag_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::untag_image_from_pool(&pool, image_id, tag_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Gets all tags for an image. +#[tauri::command] +async fn get_tags_for_image( + image_id: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let tags = CatalogManager::get_tags_for_image_from_pool(&pool, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(tags) +} + +// ============================================ +// ALBUM MANAGEMENT +// ============================================ + +/// Lists all albums. +#[tauri::command] +async fn list_albums(state: State<'_, AppState>) -> Result, String> { + let pool = get_pool(state).await?; + + let albums = CatalogManager::list_albums_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; + Ok(albums) +} + +/// Creates a new album. +#[tauri::command] +async fn create_album( + name: String, + description: Option, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let id = CatalogManager::create_album_from_pool(&pool, &name, description.as_deref()) + .await + .map_err(|e| e.to_string())?; + Ok(id) +} + +/// Deletes an album. +#[tauri::command] +async fn delete_album( + album_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::delete_album_from_pool(&pool, album_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Adds an image to an album. +#[tauri::command] +async fn add_image_to_album( + album_id: i64, + image_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::add_image_to_album_from_pool(&pool, album_id, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Removes an image from an album. +#[tauri::command] +async fn remove_image_from_album( + album_id: i64, + image_id: i64, + state: State<'_, AppState>, +) -> Result<(), String> { + let pool = get_pool(state).await?; + + CatalogManager::remove_image_from_album_from_pool(&pool, album_id, image_id) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +/// Gets all images in an album. +#[tauri::command] +async fn get_images_for_album( + album_id: i64, + offset: i64, + limit: i64, + state: State<'_, AppState>, +) -> Result, String> { + let pool = get_pool(state).await?; + + let images = CatalogManager::get_images_for_album_from_pool(&pool, album_id, offset, limit) + .await + .map_err(|e| e.to_string())?; + Ok(images) +} + +// ============================================ +// CATALOG STATS +// ============================================ + +/// Gets overall catalog statistics. +#[tauri::command] +async fn get_catalog_stats(state: State<'_, AppState>) -> Result { + let pool = get_pool(state).await?; + + let stats = CatalogManager::get_catalog_stats_from_pool(&pool) + .await + .map_err(|e| e.to_string())?; + Ok(stats) +} + +// ============================================ +// XMP EXPORT +// ============================================ + +/// Exports metadata as XMP sidecar files. +#[tauri::command] +async fn export_xmp_sidecars( + image_ids: Vec, + output_dir: String, + state: State<'_, AppState>, +) -> Result { + let pool = get_pool(state).await?; + + let exported = CatalogManager::export_xmp_sidecars_from_pool(&pool, &image_ids, &output_dir) + .await + .map_err(|e| e.to_string())?; + Ok(exported) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_fs::init()) + .plugin(tauri_plugin_shell::init()) .setup(|app| { app.manage(AppState { catalog: Mutex::new(None), @@ -218,6 +787,43 @@ pub fn run() { get_preview_path, start_face_index, upscale_image, + get_image_details, + update_rating, + toggle_favorite, + set_favorite, + archive_image, + delete_image, + delete_images, + search_images, + count_search_results, + filter_by_camera, + filter_by_lens, + filter_by_person, + filter_by_tag, + filter_by_album, + list_people, + create_person, + update_person_name, + delete_person, + assign_face_to_person, + unassign_face_from_person, + get_faces_for_image, + get_faces_for_person, + get_images_for_person, + list_tags, + create_tag, + delete_tag, + tag_image, + untag_image, + get_tags_for_image, + list_albums, + create_album, + delete_album, + add_image_to_album, + remove_image_from_album, + get_images_for_album, + get_catalog_stats, + export_xmp_sidecars, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/python/bridge.rs b/src-tauri/src/python/bridge.rs index a23d403..dc99561 100644 --- a/src-tauri/src/python/bridge.rs +++ b/src-tauri/src/python/bridge.rs @@ -1,11 +1,9 @@ use std::path::{Path, PathBuf}; -use std::process::{Child, Command, Stdio}; -use std::io::{BufRead, BufReader, Write}; -use std::sync::Arc; +use std::process::{Command, Stdio}; +use std::io::{BufRead, BufReader}; use std::time::Duration; use anyhow::{Context, Result}; -use tokio::time; /// Configuration for the Python upscaling bridge. #[derive(Debug, Clone)] @@ -133,7 +131,8 @@ impl PythonBridge { } errors.join("\n") }) - .await; + .await + .unwrap_or_default(); let error = if error_msg.is_empty() { None @@ -143,6 +142,8 @@ impl PythonBridge { progress_handle.await.ok(); + let exit_status = exit_status?; + if exit_status.success() { Ok(UpscaleResult { output_path, diff --git a/src/App.tsx b/src/App.tsx index 12e3611..de5b622 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { open, save } from "@tauri-apps/plugin-dialog"; import Toolbar from "@/components/Toolbar"; import Sidebar from "@/components/Sidebar"; import GalleryGrid from "@/components/GalleryGrid"; @@ -7,13 +7,39 @@ import { useCatalogStore } from "@/hooks/useCatalog"; const App: React.FC = () => { const { path, leftPanelVisible, rightPanelVisible } = useCatalogStore(); - const [_catalogOpen, setCatalogOpen] = useState(false); const handleOpenCatalog = async () => { - await useCatalogStore - .getState() - .openCatalog("/Users/moreno/Library/Praetorian/catalog.praetorian"); - setCatalogOpen(true); + const selected = await open({ + multiple: false, + filters: [ + { + name: "Catalog", + extensions: ["praetorian"], + }, + { + name: "All Files", + extensions: ["*"], + }, + ], + }); + if (selected && typeof selected === "string") { + await useCatalogStore.getState().openCatalog(selected); + } + }; + + const handleCreateCatalog = async () => { + const selected = await save({ + defaultPath: "library.praetorian", + filters: [ + { + name: "Catalog", + extensions: ["praetorian"], + }, + ], + }); + if (selected && typeof selected === "string") { + await useCatalogStore.getState().createCatalog(selected); + } }; return ( @@ -42,15 +68,20 @@ const App: React.FC = () => { Local-first photo library & cataloging

- -

- Or create a new .praetorian catalog file -

+
+ + +
)} diff --git a/src/components/DetailsPanel.tsx b/src/components/DetailsPanel.tsx index 8219898..7a71be6 100644 --- a/src/components/DetailsPanel.tsx +++ b/src/components/DetailsPanel.tsx @@ -87,7 +87,7 @@ const DetailsPanel: React.FC = () => { { /> diff --git a/src/components/Toolbar.tsx b/src/components/Toolbar.tsx index f85ae80..ef1acb9 100644 --- a/src/components/Toolbar.tsx +++ b/src/components/Toolbar.tsx @@ -1,12 +1,27 @@ import { useCatalogStore } from "@/hooks/useCatalog"; +import { open } from "@tauri-apps/plugin-dialog"; const Toolbar: React.FC = () => { const { path, leftPanelVisible, rightPanelVisible, toggleLeftPanel, toggleRightPanel } = useCatalogStore(); const handleOpenCatalog = async () => { - // Mock: just open with a fake path - await useCatalogStore.getState().openCatalog("/Users/moreno/Library/Praetorian/catalog.praetorian"); + const selected = await open({ + multiple: false, + filters: [ + { + name: "Catalog", + extensions: ["praetorian"], + }, + { + name: "All Files", + extensions: ["*"], + }, + ], + }); + if (selected && typeof selected === "string") { + await useCatalogStore.getState().openCatalog(selected); + } }; return ( diff --git a/src/data/mock.ts b/src/data/mock.ts deleted file mode 100644 index c3a73e9..0000000 --- a/src/data/mock.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { ImageRecord, FolderRecord, ExifData } from "@/types"; - -const NAMES = [ - "DSC001", "DSC002", "DSC003", "DSC004", "DSC005", - "IMG_4521", "IMG_4522", "IMG_4523", "IMG_4524", "IMG_4525", - "P1040001", "P1040002", "P1040003", "P1040004", "P1040005", - "R0987654", "R0987655", "R0987656", "R0987657", "R0987658", - "A001", "A002", "A003", "A004", "A005", - "MVI_0012", "MVI_0013", "MVI_0014", "MVI_0015", "MVI_0016", - "D800_001", "D800_002", "D800_003", "D800_004", "D800_005", - "X_T4521", "X_T4522", "X_T4523", "X_T4524", "X_T4525", - "C506_0001", "C506_0002", "C506_0003", "C506_0004", "C506_0005", - "ILFH8621", "ILFH8622", "ILFH8623", "ILFH8624", "ILFH8625", - "MW320101", "MW320102", "MW320103", "MW320104", "MW320105", -]; - -const EXTENSIONS = ["DNG", "CR3", "ARW", "NEF", "RAF", "jpg", "CR2", "SR2"]; -const CAMERAS = [ - { make: "Canon", model: "EOS R5" }, - { make: "Sony", model: "A7 IV" }, - { make: "Nikon", model: "Z 8" }, - { make: "Fujifilm", model: "X-T5" }, - { make: "Canon", model: "EOS 5D Mark IV" }, - { make: "Sony", model: "A7R V" }, - { make: "Nikon", model: "Z6 III" }, - { make: "Panasonic", model: "S5 II" }, -]; - -const LENSES = [ - "RF 24-70mm f/2.8L IS USM", - "FE 24-70mm f/2.8 GM II", - "Z 24-70mm f/2.8 S", - "XF 23mm f/1.4 R WM", - "RF 70-200mm f/2.8L IS USM", - "FE 85mm f/1.4 GM", - "Z 85mm f/1.2 S", - "RF 35mm f/1.8 Macro", -]; - -const LOCATIONS = [ - { lat: 37.7749, lon: -122.4194, label: "San Francisco, CA" }, - { lat: 40.7128, lon: -74.006, label: "New York, NY" }, - { lat: 51.5074, lon: -0.1278, label: "London, UK" }, - { lat: 48.8566, lon: 2.3522, label: "Paris, FR" }, - { lat: 35.6762, lon: 139.6503, label: "Tokyo, JP" }, - { lat: 34.0522, lon: -118.2437, label: "Los Angeles, CA" }, -]; - -function seededRandom(seed: number) { - let s = seed; - return () => { - s = (s * 16807 + 0) % 2147483647; - return (s - 1) / 2147483646; - }; -} - -export function generateMockImages(count: number = 60): ImageRecord[] { - const rng = seededRandom(42); - const images: ImageRecord[] = []; - - for (let i = 0; i < count; i++) { - const name = NAMES[i % NAMES.length]; - const ext = EXTENSIONS[Math.floor(rng() * EXTENSIONS.length)].toLowerCase(); - const camera = CAMERAS[Math.floor(rng() * CAMERAS.length)]; - const lens = LENSES[Math.floor(rng() * LENSES.length)]; - const location = LOCATIONS[Math.floor(rng() * LOCATIONS.length)]; - const dayOffset = Math.floor(rng() * 90); - const date = new Date(2025, 10, 15 - dayOffset); - - const width = [4256, 6000, 8192, 4928, 5472][Math.floor(rng() * 5)]; - const height = width > 5000 ? Math.round(width * 0.667) : Math.round(width * 0.75); - - images.push({ - id: i + 1, - folder_id: Math.floor(rng() * 3) + 1, - file_path: `/Volumes/SDCard/DCIM/100_CANON/${name}.${ext}`, - file_name: `${name}.${ext}`, - file_extension: ext, - file_size_bytes: Math.floor(rng() * 80_000_000) + 15_000_000, - width, - height, - date_taken: date.toISOString(), - date_imported: new Date(2025, 11, 1).toISOString(), - has_thumbnail: rng() > 0.15, - has_preview: rng() > 0.3, - rating: rng() > 0.7 ? Math.floor(rng() * 5) + 1 : 0, - is_favorite: rng() > 0.85, - faces_indexed: rng() > 0.4, - is_missing: false, - exif: { - image_id: i + 1, - camera_make: camera.make, - camera_model: camera.model, - lens_model: lens, - iso: [100, 200, 400, 800, 1600, 3200, 6400][Math.floor(rng() * 7)], - aperture: [1.4, 1.8, 2.0, 2.8, 4.0, 5.6, 8.0, 11, 16][Math.floor(rng() * 9)], - shutter_speed_num: 1, - shutter_speed_den: [60, 125, 250, 500, 1000, 2000, 4000, 8000][Math.floor(rng() * 8)], - focal_length: [24, 35, 50, 70, 85, 105, 135, 200][Math.floor(rng() * 8)], - gps_latitude: location.lat + (rng() - 0.5) * 0.01, - gps_longitude: location.lon + (rng() - 0.5) * 0.01, - gps_altitude: Math.floor(rng() * 500), - date_time_original: date.toISOString(), - }, - }); - } - - return images.sort((a, b) => - (b.date_taken ?? "").localeCompare(a.date_taken ?? "") - ); -} - -export function generateMockFolders(): FolderRecord[] { - return [ - { id: 1, path: "/Volumes/SDCard/DCIM/100_CANON", name: "100_CANON", parent_id: null, date_added: "2025-12-01T00:00:00Z", is_watched: true }, - { id: 2, path: "/Volumes/SDCard/DCIM/101_CANON", name: "101_CANON", parent_id: null, date_added: "2025-12-01T00:00:00Z", is_watched: true }, - { id: 3, path: "/Users/moreno/Photos/2025-Tokyo", name: "2025-Tokyo", parent_id: null, date_added: "2025-11-20T00:00:00Z", is_watched: false }, - { id: 4, path: "/Users/moreno/Photos/2025-Europe", name: "2025-Europe", parent_id: null, date_added: "2025-10-15T00:00:00Z", is_watched: false }, - { id: 5, path: "/Users/moreno/Photos/2025-Local", name: "2025-Local", parent_id: null, date_added: "2025-09-01T00:00:00Z", is_watched: false }, - ]; -} - -export function generateMockExif(imageId: number): ExifData | null { - const images = generateMockImages(60); - const img = images.find((i) => i.id === imageId); - return img?.exif ?? null; -} diff --git a/src/hooks/useCatalog.ts b/src/hooks/useCatalog.ts index 310d330..dc3e99c 100644 --- a/src/hooks/useCatalog.ts +++ b/src/hooks/useCatalog.ts @@ -1,24 +1,95 @@ import { create } from "zustand"; -import { CatalogState, SidebarView, FolderRecord } from "@/types"; -import { generateMockImages, generateMockFolders } from "@/data/mock"; +import { + CatalogState, + SidebarView, + FolderRecord, + ImageRecord, + PersonRecord, + TagRecord, + AlbumRecord, + CatalogStats, + FaceRecord, +} from "@/types"; +import * as catalogService from "@/services/catalog"; interface CatalogStore extends CatalogState { selectedImageIds: Set; folders: FolderRecord[]; + people: PersonRecord[]; + tags: TagRecord[]; + albums: AlbumRecord[]; + stats: CatalogStats | null; activeView: SidebarView; leftPanelVisible: boolean; rightPanelVisible: boolean; + // Catalog operations openCatalog: (path: string) => Promise; + createCatalog: (path: string) => Promise; + loadImages: (offset?: number, limit?: number) => Promise; + loadFolders: () => Promise; + loadStats: () => Promise; + + // Import importDirectory: (dirPath: string) => Promise; + + // Image selection selectImage: (id: number) => void; deselectImage: (id: number) => void; clearSelection: () => void; + getSelectedImages: () => ImageRecord[]; + + // Navigation setActiveView: (view: SidebarView) => void; toggleLeftPanel: () => void; toggleRightPanel: () => void; - updateRating: (id: number, rating: number) => void; - toggleFavorite: (id: number) => void; + + // Rating & favorites + updateRating: (id: number, rating: number) => Promise; + toggleFavorite: (id: number) => Promise; + + // Archive & delete + archiveImage: (id: number, isArchived: boolean) => Promise; + deleteImage: (id: number) => Promise; + deleteSelectedImages: () => Promise; + + // Search & filter + searchImages: ( + query: string, + offset?: number, + limit?: number + ) => Promise; + + // People + loadPeople: () => Promise; + createPerson: (name: string) => Promise; + updatePersonName: (personId: number, name: string) => Promise; + deletePerson: (personId: number) => Promise; + assignFaceToPerson: (faceId: number, personId: number) => Promise; + unassignFaceFromPerson: (faceId: number) => Promise; + loadImagesForPerson: (personId: number) => Promise; + + // Tags + loadTags: () => Promise; + createTag: (name: string, color?: string) => Promise; + deleteTag: (tagId: number) => Promise; + tagImage: (imageId: number, tagId: number) => Promise; + untagImage: (imageId: number, tagId: number) => Promise; + + // Albums + loadAlbums: () => Promise; + createAlbum: (name: string, description?: string) => Promise; + deleteAlbum: (albumId: number) => Promise; + addImageToAlbum: (albumId: number, imageId: number) => Promise; + removeImageFromAlbum: (albumId: number, imageId: number) => Promise; + loadImagesForAlbum: (albumId: number) => Promise; + + // Face detection + startFaceIndex: () => Promise; + getFacesForImage: (imageId: number) => Promise; + + // Export + exportXmpSidecars: (outputDir: string) => Promise; } export const useCatalogStore = create((set, get) => ({ @@ -29,38 +100,81 @@ export const useCatalogStore = create((set, get) => ({ error: null, selectedImageIds: new Set(), folders: [], + people: [], + tags: [], + albums: [], + stats: null, activeView: "library", leftPanelVisible: true, rightPanelVisible: true, openCatalog: async (path: string) => { set({ isLoading: true, error: null }); - // Simulate async load - await new Promise((r) => setTimeout(r, 300)); - const images = generateMockImages(60); - const folders = generateMockFolders(); - set({ - path, - images, - totalImages: images.length, - folders, - isLoading: false, - }); - }, - - importDirectory: async (_dirPath: string) => { - await new Promise((r) => setTimeout(r, 500)); - const current = get().images; - const newImages = generateMockImages(12).map((img, i) => ({ - ...img, - id: current.length + i + 1, - })); - const updated = [...current, ...newImages]; - set({ - images: updated, - totalImages: updated.length, - }); - return newImages.length; + try { + await catalogService.openCatalog(path); + await get().loadImages(); + await get().loadFolders(); + await get().loadStats(); + set({ path, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Failed to open catalog", isLoading: false }); + } + }, + + createCatalog: async (path: string) => { + set({ isLoading: true, error: null }); + try { + await catalogService.createCatalog(path); + set({ path, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Failed to create catalog", isLoading: false }); + } + }, + + loadImages: async (offset = 0, limit = 60) => { + set({ isLoading: true, error: null }); + try { + const [images, total] = await Promise.all([ + catalogService.listImages(offset, limit), + catalogService.countImages(), + ]); + set({ images, totalImages: total, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Failed to load images", isLoading: false }); + } + }, + + loadFolders: async () => { + try { + const folders = await catalogService.listFolders(); + set({ folders }); + } catch (e: any) { + console.error("Failed to load folders:", e); + } + }, + + loadStats: async () => { + try { + const stats = await catalogService.getCatalogStats(); + set({ stats }); + } catch (e: any) { + console.error("Failed to load stats:", e); + } + }, + + importDirectory: async (dirPath: string) => { + set({ isLoading: true }); + try { + const imported = await catalogService.importDirectory(dirPath); + await get().loadImages(); + await get().loadFolders(); + await get().loadStats(); + set({ isLoading: false }); + return imported; + } catch (e: any) { + set({ error: e.message || "Failed to import directory", isLoading: false }); + throw e; + } }, selectImage: (id: number) => { @@ -81,6 +195,11 @@ export const useCatalogStore = create((set, get) => ({ set({ selectedImageIds: new Set() }); }, + getSelectedImages: () => { + const { images, selectedImageIds } = get(); + return images.filter((img) => selectedImageIds.has(img.id)); + }, + setActiveView: (view: SidebarView) => { set({ activeView: view }); }, @@ -93,19 +212,280 @@ export const useCatalogStore = create((set, get) => ({ set((s) => ({ rightPanelVisible: !s.rightPanelVisible })); }, - updateRating: (id: number, rating: number) => { - set((s) => ({ - images: s.images.map((img) => - img.id === id ? { ...img, rating } : img - ), - })); + updateRating: async (id: number, rating: number) => { + try { + await catalogService.updateRating(id, rating); + set((s) => ({ + images: s.images.map((img) => + img.id === id ? { ...img, rating } : img + ), + })); + } catch (e: any) { + set({ error: e.message || "Failed to update rating" }); + } }, - toggleFavorite: (id: number) => { - set((s) => ({ - images: s.images.map((img) => - img.id === id ? { ...img, is_favorite: !img.is_favorite } : img - ), - })); + toggleFavorite: async (id: number) => { + try { + const newFavorite = await catalogService.toggleFavorite(id); + set((s) => ({ + images: s.images.map((img) => + img.id === id ? { ...img, is_favorite: newFavorite } : img + ), + })); + } catch (e: any) { + set({ error: e.message || "Failed to toggle favorite" }); + } + }, + + archiveImage: async (id: number, isArchived: boolean) => { + try { + await catalogService.archiveImage(id, isArchived); + set((s) => ({ + images: s.images.filter((img) => img.id !== id), + totalImages: s.totalImages - 1, + })); + } catch (e: any) { + set({ error: e.message || "Failed to archive image" }); + } + }, + + deleteImage: async (id: number) => { + try { + await catalogService.deleteImage(id); + set((s) => ({ + images: s.images.filter((img) => img.id !== id), + totalImages: s.totalImages - 1, + selectedImageIds: new Set( + [...s.selectedImageIds].filter((x) => x !== id) + ), + })); + } catch (e: any) { + set({ error: e.message || "Failed to delete image" }); + } + }, + + deleteSelectedImages: async () => { + const { selectedImageIds } = get(); + if (selectedImageIds.size === 0) return; + try { + const ids = [...selectedImageIds]; + await catalogService.deleteImages(ids); + set((s) => ({ + images: s.images.filter((img) => !selectedImageIds.has(img.id)), + totalImages: s.totalImages - ids.length, + selectedImageIds: new Set(), + })); + } catch (e: any) { + set({ error: e.message || "Failed to delete images" }); + } + }, + + searchImages: async (query: string, offset = 0, limit = 60) => { + set({ isLoading: true }); + try { + const [images, total] = await Promise.all([ + catalogService.searchImages(query, offset, limit), + catalogService.countSearchResults(query), + ]); + set({ images, totalImages: total, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Search failed", isLoading: false }); + } + }, + + loadPeople: async () => { + try { + const people = await catalogService.listPeople(); + set({ people }); + } catch (e: any) { + console.error("Failed to load people:", e); + } + }, + + createPerson: async (name: string) => { + try { + await catalogService.createPerson(name); + await get().loadPeople(); + } catch (e: any) { + set({ error: e.message || "Failed to create person" }); + } + }, + + updatePersonName: async (personId: number, name: string) => { + try { + await catalogService.updatePersonName(personId, name); + set((s) => ({ + people: s.people.map((p) => + p.id === personId ? { ...p, name, updated_at: new Date().toISOString() } : p + ), + })); + } catch (e: any) { + set({ error: e.message || "Failed to update person name" }); + } + }, + + deletePerson: async (personId: number) => { + try { + await catalogService.deletePerson(personId); + set((s) => ({ + people: s.people.filter((p) => p.id !== personId), + })); + } catch (e: any) { + set({ error: e.message || "Failed to delete person" }); + } + }, + + assignFaceToPerson: async (faceId: number, personId: number) => { + try { + await catalogService.assignFaceToPerson(faceId, personId); + } catch (e: any) { + set({ error: e.message || "Failed to assign face to person" }); + } + }, + + unassignFaceFromPerson: async (faceId: number) => { + try { + await catalogService.unassignFaceFromPerson(faceId); + } catch (e: any) { + set({ error: e.message || "Failed to unassign face" }); + } + }, + + loadImagesForPerson: async (personId: number) => { + set({ isLoading: true }); + try { + const images = await catalogService.filterByPerson(personId, 0, 1000); + set({ images, totalImages: images.length, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Failed to load images for person", isLoading: false }); + } + }, + + loadTags: async () => { + try { + const tags = await catalogService.listTags(); + set({ tags }); + } catch (e: any) { + console.error("Failed to load tags:", e); + } + }, + + createTag: async (name: string, color?: string) => { + try { + await catalogService.createTag(name, color ?? null); + await get().loadTags(); + } catch (e: any) { + set({ error: e.message || "Failed to create tag" }); + } + }, + + deleteTag: async (tagId: number) => { + try { + await catalogService.deleteTag(tagId); + set((s) => ({ + tags: s.tags.filter((t) => t.id !== tagId), + })); + } catch (e: any) { + set({ error: e.message || "Failed to delete tag" }); + } + }, + + tagImage: async (imageId: number, tagId: number) => { + try { + await catalogService.tagImage(imageId, tagId); + } catch (e: any) { + set({ error: e.message || "Failed to tag image" }); + } + }, + + untagImage: async (imageId: number, tagId: number) => { + try { + await catalogService.untagImage(imageId, tagId); + } catch (e: any) { + set({ error: e.message || "Failed to untag image" }); + } + }, + + loadAlbums: async () => { + try { + const albums = await catalogService.listAlbums(); + set({ albums }); + } catch (e: any) { + console.error("Failed to load albums:", e); + } + }, + + createAlbum: async (name: string, description?: string) => { + try { + await catalogService.createAlbum(name, description ?? null); + await get().loadAlbums(); + } catch (e: any) { + set({ error: e.message || "Failed to create album" }); + } + }, + + deleteAlbum: async (albumId: number) => { + try { + await catalogService.deleteAlbum(albumId); + set((s) => ({ + albums: s.albums.filter((a) => a.id !== albumId), + })); + } catch (e: any) { + set({ error: e.message || "Failed to delete album" }); + } + }, + + addImageToAlbum: async (albumId: number, imageId: number) => { + try { + await catalogService.addImageToAlbum(albumId, imageId); + } catch (e: any) { + set({ error: e.message || "Failed to add image to album" }); + } + }, + + removeImageFromAlbum: async (albumId: number, imageId: number) => { + try { + await catalogService.removeImageFromAlbum(albumId, imageId); + } catch (e: any) { + set({ error: e.message || "Failed to remove image from album" }); + } + }, + + loadImagesForAlbum: async (albumId: number) => { + set({ isLoading: true }); + try { + const images = await catalogService.filterByAlbum(albumId, 0, 1000); + set({ images, totalImages: images.length, isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Failed to load images for album", isLoading: false }); + } + }, + + startFaceIndex: async () => { + set({ isLoading: true }); + try { + await catalogService.startFaceIndex(); + await get().loadStats(); + set({ isLoading: false }); + } catch (e: any) { + set({ error: e.message || "Face indexing failed", isLoading: false }); + } + }, + + getFacesForImage: async (imageId: number) => { + return catalogService.getFacesForImage(imageId); + }, + + exportXmpSidecars: async (outputDir: string) => { + const { selectedImageIds } = get(); + const ids = [...selectedImageIds]; + if (ids.length === 0) return 0; + try { + return await catalogService.exportXmpSidecars(ids, outputDir); + } catch (e: any) { + set({ error: e.message || "Failed to export XMP" }); + return 0; + } }, })); diff --git a/src/services/catalog.ts b/src/services/catalog.ts index 13c4401..4098996 100644 --- a/src/services/catalog.ts +++ b/src/services/catalog.ts @@ -1,5 +1,18 @@ import { invoke } from "@tauri-apps/api/core"; -import { ImageRecord, FolderRecord } from "../types"; +import { + ImageRecord, + FolderRecord, + ExifData, + FaceRecord, + PersonRecord, + TagRecord, + AlbumRecord, + CatalogStats, +} from "../types"; + +// ============================================ +// CATALOG +// ============================================ export async function openCatalog(path: string): Promise { return invoke("open_catalog", { path }); @@ -9,10 +22,22 @@ export async function createCatalog(path: string): Promise { return invoke("create_catalog", { path }); } +export async function getCatalogStats(): Promise { + return invoke("get_catalog_stats"); +} + +// ============================================ +// IMPORT +// ============================================ + export async function importDirectory(dirPath: string): Promise { return invoke("import_directory", { dirPath }); } +// ============================================ +// IMAGE LISTING +// ============================================ + export async function listImages( offset: number, limit: number, @@ -33,6 +58,20 @@ export async function listFolders(): Promise { return invoke("list_folders"); } +// ============================================ +// IMAGE DETAILS +// ============================================ + +export async function getImageDetails( + imageId: number +): Promise { + return invoke("get_image_details", { imageId }); +} + +// ============================================ +// THUMBNAILS & PREVIEWS +// ============================================ + export async function getThumbnailPath(imageId: number): Promise { return invoke("get_thumbnail_path", { imageId }); } @@ -41,10 +80,266 @@ export async function getPreviewPath(imageId: number): Promise { return invoke("get_preview_path", { imageId }); } +// ============================================ +// RATING & FAVORITES +// ============================================ + +export async function updateRating( + imageId: number, + rating: number +): Promise { + return invoke("update_rating", { imageId, rating }); +} + +export async function toggleFavorite(imageId: number): Promise { + return invoke("toggle_favorite", { imageId }); +} + +export async function setFavorite( + imageId: number, + isFavorite: boolean +): Promise { + return invoke("set_favorite", { imageId, isFavorite }); +} + +// ============================================ +// ARCHIVE & DELETE +// ============================================ + +export async function archiveImage( + imageId: number, + isArchived: boolean +): Promise { + return invoke("archive_image", { imageId, isArchived }); +} + +export async function deleteImage(imageId: number): Promise { + return invoke("delete_image", { imageId }); +} + +export async function deleteImages(imageIds: number[]): Promise { + return invoke("delete_images", { imageIds }); +} + +// ============================================ +// SEARCH & FILTER +// ============================================ + +export async function searchImages( + query: string, + offset: number, + limit: number +): Promise { + return invoke("search_images", { query, offset, limit }); +} + +export async function countSearchResults(query: string): Promise { + return invoke("count_search_results", { query }); +} + +export async function filterByCamera( + cameraModel: string, + offset: number, + limit: number +): Promise { + return invoke("filter_by_camera", { + cameraModel, + offset, + limit, + }); +} + +export async function filterByLens( + lensModel: string, + offset: number, + limit: number +): Promise { + return invoke("filter_by_lens", { + lensModel, + offset, + limit, + }); +} + +export async function filterByPerson( + personId: number, + offset: number, + limit: number +): Promise { + return invoke("filter_by_person", { + personId, + offset, + limit, + }); +} + +export async function filterByTag( + tagId: number, + offset: number, + limit: number +): Promise { + return invoke("filter_by_tag", { tagId, offset, limit }); +} + +export async function filterByAlbum( + albumId: number, + offset: number, + limit: number +): Promise { + return invoke("filter_by_album", { + albumId, + offset, + limit, + }); +} + +// ============================================ +// FACE DETECTION +// ============================================ + export async function startFaceIndex(): Promise { return invoke("start_face_index"); } +export async function getFacesForImage( + imageId: number +): Promise { + return invoke("get_faces_for_image", { imageId }); +} + +// ============================================ +// PEOPLE MANAGEMENT +// ============================================ + +export async function listPeople(): Promise { + return invoke("list_people"); +} + +export async function createPerson(name: string): Promise { + return invoke("create_person", { name }); +} + +export async function updatePersonName( + personId: number, + name: string +): Promise { + return invoke("update_person_name", { personId, name }); +} + +export async function deletePerson(personId: number): Promise { + return invoke("delete_person", { personId }); +} + +export async function assignFaceToPerson( + faceId: number, + personId: number +): Promise { + return invoke("assign_face_to_person", { faceId, personId }); +} + +export async function unassignFaceFromPerson( + faceId: number +): Promise { + return invoke("unassign_face_from_person", { faceId }); +} + +export async function getFacesForPerson( + personId: number +): Promise { + return invoke("get_faces_for_person", { personId }); +} + +export async function getImagesForPerson( + personId: number +): Promise { + return invoke("get_images_for_person", { personId }); +} + +// ============================================ +// TAG MANAGEMENT +// ============================================ + +export async function listTags(): Promise { + return invoke("list_tags"); +} + +export async function createTag( + name: string, + color?: string | null +): Promise { + return invoke("create_tag", { name, color }); +} + +export async function deleteTag(tagId: number): Promise { + return invoke("delete_tag", { tagId }); +} + +export async function tagImage(imageId: number, tagId: number): Promise { + return invoke("tag_image", { imageId, tagId }); +} + +export async function untagImage( + imageId: number, + tagId: number +): Promise { + return invoke("untag_image", { imageId, tagId }); +} + +export async function getTagsForImage( + imageId: number +): Promise { + return invoke("get_tags_for_image", { imageId }); +} + +// ============================================ +// ALBUM MANAGEMENT +// ============================================ + +export async function listAlbums(): Promise { + return invoke("list_albums"); +} + +export async function createAlbum( + name: string, + description?: string | null +): Promise { + return invoke("create_album", { name, description }); +} + +export async function deleteAlbum(albumId: number): Promise { + return invoke("delete_album", { albumId }); +} + +export async function addImageToAlbum( + albumId: number, + imageId: number +): Promise { + return invoke("add_image_to_album", { albumId, imageId }); +} + +export async function removeImageFromAlbum( + albumId: number, + imageId: number +): Promise { + return invoke("remove_image_from_album", { albumId, imageId }); +} + +export async function getImagesForAlbum( + albumId: number, + offset: number, + limit: number +): Promise { + return invoke("get_images_for_album", { + albumId, + offset, + limit, + }); +} + +// ============================================ +// AI & PROCESSING +// ============================================ + export async function upscaleImage( imagePath: string, outputDir: string, @@ -52,3 +347,14 @@ export async function upscaleImage( ): Promise { return invoke("upscale_image", { imagePath, outputDir, scale }); } + +// ============================================ +// EXPORT +// ============================================ + +export async function exportXmpSidecars( + imageIds: number[], + outputDir: string +): Promise { + return invoke("export_xmp_sidecars", { imageIds, outputDir }); +} diff --git a/src/types/index.ts b/src/types/index.ts index 4a33463..1eb40cc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -24,14 +24,13 @@ export interface ExifData { camera_model: string | null; lens_model: string | null; iso: number | null; - aperture: number | null; + aperture_f_number: number | null; shutter_speed_num: number | null; shutter_speed_den: number | null; - focal_length: number | null; + focal_length_mm: number | null; gps_latitude: number | null; gps_longitude: number | null; gps_altitude: number | null; - date_time_original: string | null; } export interface FolderRecord { @@ -43,7 +42,7 @@ export interface FolderRecord { is_watched: boolean; } -export interface FaceDetection { +export interface FaceRecord { id: number; image_id: number; person_id: number | null; @@ -54,11 +53,35 @@ export interface FaceDetection { confidence: number; } -export interface Person { +export interface PersonRecord { id: number; name: string; created_at: string; updated_at: string; + face_count: number; +} + +export interface TagRecord { + id: number; + name: string; + color: string | null; +} + +export interface AlbumRecord { + id: number; + name: string; + description: string | null; + created_at: string; +} + +export interface CatalogStats { + total_images: number; + total_faces: number; + total_people: number; + total_folders: number; + total_tags: number; + unindexed_faces: number; + missing_files: number; } export interface CatalogState {