diff --git a/package.json b/package.json index 268ac666..e3fcda77 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "@tanstack/query-persist-client-core": "^5.51.21", "@tanstack/react-query": "^5.51.23", "@tanstack/react-router": "^1.48.1", + "@tanstack/react-store": "^0.5.5", + "@tanstack/store": "^0.5.5", "@tauri-apps/api": "2.0.0-rc.1", "@tauri-apps/plugin-clipboard-manager": "2.0.0-rc.0", "@tauri-apps/plugin-dialog": "2.0.0-rc.0", @@ -30,10 +32,12 @@ "@tauri-apps/plugin-os": "2.0.0-rc.0", "@tauri-apps/plugin-process": "2.0.0-rc.0", "@tauri-apps/plugin-shell": "2.0.0-rc.0", + "@tauri-apps/plugin-store": "2.0.0-rc.0", "@tauri-apps/plugin-updater": "2.0.0-rc.0", "@tauri-apps/plugin-upload": "2.0.0-rc.0", "@tauri-apps/plugin-window-state": "2.0.0-rc.0", "bitcoin-units": "^1.0.0", + "boring-avatars": "^1.10.2", "dayjs": "^1.11.12", "embla-carousel-react": "^8.1.8", "i18next": "^23.13.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5717aadb..2021d137 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,12 @@ importers: '@tanstack/react-router': specifier: ^1.48.1 version: 1.48.1(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722) + '@tanstack/react-store': + specifier: ^0.5.5 + version: 0.5.5(react-dom@19.0.0-rc-d025ddd3-20240722(react@19.0.0-rc-d025ddd3-20240722))(react@19.0.0-rc-d025ddd3-20240722) + '@tanstack/store': + specifier: ^0.5.5 + version: 0.5.5 '@tauri-apps/api': specifier: 2.0.0-rc.1 version: 2.0.0-rc.1 @@ -68,6 +74,9 @@ importers: '@tauri-apps/plugin-shell': specifier: 2.0.0-rc.0 version: 2.0.0-rc.0 + '@tauri-apps/plugin-store': + specifier: 2.0.0-rc.0 + version: 2.0.0-rc.0 '@tauri-apps/plugin-updater': specifier: 2.0.0-rc.0 version: 2.0.0-rc.0 @@ -80,6 +89,9 @@ importers: bitcoin-units: specifier: ^1.0.0 version: 1.0.0 + boring-avatars: + specifier: ^1.10.2 + version: 1.10.2 dayjs: specifier: ^1.11.12 version: 1.11.12 @@ -1214,6 +1226,9 @@ packages: '@tauri-apps/plugin-shell@2.0.0-rc.0': resolution: {integrity: sha512-bhUcQcrqZoK8H1DFXapr5r1Z75oh6Kd5Tltz97XpZFLREEqp+KhN2Fvyh8r/fKAyenYsTYUIsDsyGdjdueuF9g==} + '@tauri-apps/plugin-store@2.0.0-rc.0': + resolution: {integrity: sha512-KqiEzq6EdRwxrl0/FwyNLwumDBM91xTchdu2a8vfkNub30GuP9z7RskP9ifVRI1gbxfa5TUDi0hKFk/SP7TANQ==} + '@tauri-apps/plugin-updater@2.0.0-rc.0': resolution: {integrity: sha512-EKajf/sBpFif0cwXhTo3BmNvTZ2t2DDLRyhA8FFKugZNoOeqU97bHhPT5DIqMUPRE1tyDk9o7sXm8dKf7oz+EA==} @@ -1340,6 +1355,9 @@ packages: bitcoin-units@1.0.0: resolution: {integrity: sha512-brac+Ttz7ovf/8D0jQHSWHnN2hmdjxDRBStxhjO752URLJlQIFpfZxzUteSZ81UYnRNiMkvsW9WsYPDuxHfnYA==} + boring-avatars@1.10.2: + resolution: {integrity: sha512-uQyvmNeW6loz4Yytj7aDo0IhhuByW/YyOHtqwb3kQ/x48hum22hROA2Wn3qzrLR5JsoZ+FHjPO6z6LrXrWjegg==} + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -3160,6 +3178,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.0.0-rc.1 + '@tauri-apps/plugin-store@2.0.0-rc.0': + dependencies: + '@tauri-apps/api': 2.0.0-rc.1 + '@tauri-apps/plugin-updater@2.0.0-rc.0': dependencies: '@tauri-apps/api': 2.0.0-rc.1 @@ -3304,6 +3326,8 @@ snapshots: dependencies: big.js: 6.2.1 + boring-avatars@1.10.2: {} + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ee10e83e..ae1985f4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8,6 +8,49 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +[[package]] +name = "Lume" +version = "4.0.0" +dependencies = [ + "border", + "cocoa 0.25.0", + "futures", + "keyring", + "keyring-search", + "linkify", + "monitor", + "nostr-sdk", + "objc", + "rand 0.8.5", + "regex", + "reqwest", + "serde", + "serde_json", + "specta", + "specta-typescript", + "tauri", + "tauri-build", + "tauri-nspanel", + "tauri-plugin-clipboard-manager", + "tauri-plugin-decorum", + "tauri-plugin-dialog", + "tauri-plugin-fs", + "tauri-plugin-http", + "tauri-plugin-notification", + "tauri-plugin-os", + "tauri-plugin-prevent-default", + "tauri-plugin-process", + "tauri-plugin-shell", + "tauri-plugin-store", + "tauri-plugin-theme", + "tauri-plugin-updater", + "tauri-plugin-upload", + "tauri-plugin-window-state", + "tauri-specta", + "tokio", + "url", +] + [[package]] name = "addr2line" version = "0.22.0" @@ -2936,48 +2979,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "lume" -version = "4.0.0" -dependencies = [ - "border", - "cocoa 0.25.0", - "futures", - "keyring", - "keyring-search", - "linkify", - "monitor", - "nostr-sdk", - "objc", - "rand 0.8.5", - "regex", - "reqwest", - "serde", - "serde_json", - "specta", - "specta-typescript", - "tauri", - "tauri-build", - "tauri-nspanel", - "tauri-plugin-clipboard-manager", - "tauri-plugin-decorum", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-http", - "tauri-plugin-notification", - "tauri-plugin-os", - "tauri-plugin-prevent-default", - "tauri-plugin-process", - "tauri-plugin-shell", - "tauri-plugin-theme", - "tauri-plugin-updater", - "tauri-plugin-upload", - "tauri-plugin-window-state", - "tauri-specta", - "tokio", - "url", -] - [[package]] name = "mac" version = "0.1.1" @@ -5678,9 +5679,9 @@ dependencies = [ [[package]] name = "tauri-plugin-prevent-default" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ee986aa5872bfa37762e06d86e60325f721d602a436165f4be34a16ff8ae3e" +checksum = "02858534169f6f6276ba723a00b6a4582b6606c4da47451406fc01f212423aec" dependencies = [ "bitflags 2.6.0", "itertools", @@ -5722,6 +5723,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "tauri-plugin-store" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfc658c2fe037e25e8af70d72ce2a757203be3fd8db13893fe872fa9847f9cac" +dependencies = [ + "dunce", + "log", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror", +] + [[package]] name = "tauri-plugin-theme" version = "0.4.1" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 98d44d8f..c94ef28f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "lume" +name = "Lume" version = "4.0.0" description = "nostr client" authors = ["npub1zfss807aer0j26mwp2la0ume0jqde3823rmu97ra6sgyyg956e0s6xw445"] @@ -34,9 +34,10 @@ tauri-plugin-process = "2.0.0-rc" tauri-plugin-shell = "2.0.0-rc" tauri-plugin-updater = "2.0.0-rc" tauri-plugin-upload = "2.0.0-rc" +tauri-plugin-store = "2.0.0-rc" tauri-plugin-theme = "0.4.1" tauri-plugin-decorum = "1.0.0" -tauri-plugin-prevent-default = "0.3" +tauri-plugin-prevent-default = "0.4" tauri-specta = { version = "2.0.0-rc.15", features = ["derive", "typescript"] } specta = "^2.0.0-rc.20" specta-typescript = "0.0.7" diff --git a/src-tauri/capabilities/column.json b/src-tauri/capabilities/column.json index 63a50434..497a8282 100644 --- a/src-tauri/capabilities/column.json +++ b/src-tauri/capabilities/column.json @@ -25,6 +25,9 @@ "core:menu:allow-popup", "http:default", "shell:allow-open", + "store:allow-get", + "store:allow-set", + "store:allow-delete", { "identifier": "http:default", "allow": [ diff --git a/src-tauri/capabilities/main.json b/src-tauri/capabilities/main.json index d1f0198b..c42d0bc7 100644 --- a/src-tauri/capabilities/main.json +++ b/src-tauri/capabilities/main.json @@ -3,7 +3,6 @@ "identifier": "desktop-capability", "description": "Capability for the desktop", "platforms": [ - "linux", "macOS", "windows" ], @@ -63,6 +62,9 @@ "core:menu:allow-new", "core:menu:allow-popup", "shell:allow-open", + "store:allow-get", + "store:allow-set", + "store:allow-delete", "prevent-default:default", { "identifier": "http:default", diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json index fcbd779d..3d539a85 100644 --- a/src-tauri/gen/schemas/acl-manifests.json +++ b/src-tauri/gen/schemas/acl-manifests.json @@ -1 +1 @@ -{"clipboard-manager":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n","permissions":[]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-read-image":{"identifier":"allow-read-image","description":"Enables the read_image command without any pre-configured scope.","commands":{"allow":["read_image"],"deny":[]}},"allow-read-text":{"identifier":"allow-read-text","description":"Enables the read_text command without any pre-configured scope.","commands":{"allow":["read_text"],"deny":[]}},"allow-write-html":{"identifier":"allow-write-html","description":"Enables the write_html command without any pre-configured scope.","commands":{"allow":["write_html"],"deny":[]}},"allow-write-image":{"identifier":"allow-write-image","description":"Enables the write_image command without any pre-configured scope.","commands":{"allow":["write_image"],"deny":[]}},"allow-write-text":{"identifier":"allow-write-text","description":"Enables the write_text command without any pre-configured scope.","commands":{"allow":["write_text"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-read-image":{"identifier":"deny-read-image","description":"Denies the read_image command without any pre-configured scope.","commands":{"allow":[],"deny":["read_image"]}},"deny-read-text":{"identifier":"deny-read-text","description":"Denies the read_text command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text"]}},"deny-write-html":{"identifier":"deny-write-html","description":"Denies the write_html command without any pre-configured scope.","commands":{"allow":[],"deny":["write_html"]}},"deny-write-image":{"identifier":"deny-write-image","description":"Denies the write_image command without any pre-configured scope.","commands":{"allow":[],"deny":["write_image"]}},"deny-write-text":{"identifier":"deny-write-text","description":"Denies the write_text command without any pre-configured scope.","commands":{"allow":[],"deny":["write_text"]}}},"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"]},"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-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-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"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-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-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"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.","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.","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.","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.","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.","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.","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-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-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-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-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-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-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"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-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-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-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"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-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-internal-toggle-maximize"]},"permissions":{"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-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-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-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-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-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"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-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-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-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-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-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-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-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-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-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"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-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-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-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},"decorum":{"default_permission":null,"permissions":{"allow-show-snap-overlay":{"identifier":"allow-show-snap-overlay","description":"Enables the show_snap_overlay command without any pre-configured scope.","commands":{"allow":["show_snap_overlay"],"deny":[]}},"deny-show-snap-overlay":{"identifier":"deny-show-snap-overlay","description":"Denies the show_snap_overlay command without any pre-configured scope.","commands":{"allow":[],"deny":["show_snap_overlay"]}}},"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-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"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.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"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\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"],"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-stat":{"identifier":"allow-stat","description":"Enables the stat command without any pre-configured scope.","commands":{"allow":["stat"],"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"],"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"],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"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-stat":{"identifier":"deny-stat","description":"Denies the stat command without any pre-configured scope.","commands":{"allow":[],"deny":["stat"]}},"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"],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG/**"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE/**"},{"path":"$APPLOG/**"}]}},"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"],"deny":[]}},"scope":{"identifier":"scope","description":"An empty permission you can use to modify the global scope.","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 `$APP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the `$APP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete `$APP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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 `$APP` folder, 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 `$APP` folder, 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 `$APP` folder.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete `$APP` folder, 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 `$APP` folder.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete `$APP` folder, 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":"FS scope path.","type":"string"},{"properties":{"path":{"description":"FS scope path.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"http":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n","permissions":["allow-fetch","allow-fetch-cancel","allow-fetch-read-body","allow-fetch-send"]},"permissions":{"allow-fetch":{"identifier":"allow-fetch","description":"Enables the fetch command without any pre-configured scope.","commands":{"allow":["fetch"],"deny":[]}},"allow-fetch-cancel":{"identifier":"allow-fetch-cancel","description":"Enables the fetch_cancel command without any pre-configured scope.","commands":{"allow":["fetch_cancel"],"deny":[]}},"allow-fetch-read-body":{"identifier":"allow-fetch-read-body","description":"Enables the fetch_read_body command without any pre-configured scope.","commands":{"allow":["fetch_read_body"],"deny":[]}},"allow-fetch-send":{"identifier":"allow-fetch-send","description":"Enables the fetch_send command without any pre-configured scope.","commands":{"allow":["fetch_send"],"deny":[]}},"deny-fetch":{"identifier":"deny-fetch","description":"Denies the fetch command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch"]}},"deny-fetch-cancel":{"identifier":"deny-fetch-cancel","description":"Denies the fetch_cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_cancel"]}},"deny-fetch-read-body":{"identifier":"deny-fetch-read-body","description":"Denies the fetch_read_body command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_read_body"]}},"deny-fetch-send":{"identifier":"deny-fetch-send","description":"Denies the fetch_send command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_send"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"},{"properties":{"url":{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"}],"description":"HTTP scope entry.","title":"HttpScopeEntry"}},"notification":{"default_permission":{"identifier":"default","description":"This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n","permissions":["allow-is-permission-granted","allow-request-permission","allow-notify","allow-register-action-types","allow-register-listener","allow-cancel","allow-get-pending","allow-remove-active","allow-get-active","allow-check-permissions","allow-show","allow-batch","allow-list-channels","allow-delete-channel","allow-create-channel","allow-permission-state"]},"permissions":{"allow-batch":{"identifier":"allow-batch","description":"Enables the batch command without any pre-configured scope.","commands":{"allow":["batch"],"deny":[]}},"allow-cancel":{"identifier":"allow-cancel","description":"Enables the cancel command without any pre-configured scope.","commands":{"allow":["cancel"],"deny":[]}},"allow-check-permissions":{"identifier":"allow-check-permissions","description":"Enables the check_permissions command without any pre-configured scope.","commands":{"allow":["check_permissions"],"deny":[]}},"allow-create-channel":{"identifier":"allow-create-channel","description":"Enables the create_channel command without any pre-configured scope.","commands":{"allow":["create_channel"],"deny":[]}},"allow-delete-channel":{"identifier":"allow-delete-channel","description":"Enables the delete_channel command without any pre-configured scope.","commands":{"allow":["delete_channel"],"deny":[]}},"allow-get-active":{"identifier":"allow-get-active","description":"Enables the get_active command without any pre-configured scope.","commands":{"allow":["get_active"],"deny":[]}},"allow-get-pending":{"identifier":"allow-get-pending","description":"Enables the get_pending command without any pre-configured scope.","commands":{"allow":["get_pending"],"deny":[]}},"allow-is-permission-granted":{"identifier":"allow-is-permission-granted","description":"Enables the is_permission_granted command without any pre-configured scope.","commands":{"allow":["is_permission_granted"],"deny":[]}},"allow-list-channels":{"identifier":"allow-list-channels","description":"Enables the list_channels command without any pre-configured scope.","commands":{"allow":["list_channels"],"deny":[]}},"allow-notify":{"identifier":"allow-notify","description":"Enables the notify command without any pre-configured scope.","commands":{"allow":["notify"],"deny":[]}},"allow-permission-state":{"identifier":"allow-permission-state","description":"Enables the permission_state command without any pre-configured scope.","commands":{"allow":["permission_state"],"deny":[]}},"allow-register-action-types":{"identifier":"allow-register-action-types","description":"Enables the register_action_types command without any pre-configured scope.","commands":{"allow":["register_action_types"],"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-active":{"identifier":"allow-remove-active","description":"Enables the remove_active command without any pre-configured scope.","commands":{"allow":["remove_active"],"deny":[]}},"allow-request-permission":{"identifier":"allow-request-permission","description":"Enables the request_permission command without any pre-configured scope.","commands":{"allow":["request_permission"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"deny-batch":{"identifier":"deny-batch","description":"Denies the batch command without any pre-configured scope.","commands":{"allow":[],"deny":["batch"]}},"deny-cancel":{"identifier":"deny-cancel","description":"Denies the cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["cancel"]}},"deny-check-permissions":{"identifier":"deny-check-permissions","description":"Denies the check_permissions command without any pre-configured scope.","commands":{"allow":[],"deny":["check_permissions"]}},"deny-create-channel":{"identifier":"deny-create-channel","description":"Denies the create_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["create_channel"]}},"deny-delete-channel":{"identifier":"deny-delete-channel","description":"Denies the delete_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["delete_channel"]}},"deny-get-active":{"identifier":"deny-get-active","description":"Denies the get_active command without any pre-configured scope.","commands":{"allow":[],"deny":["get_active"]}},"deny-get-pending":{"identifier":"deny-get-pending","description":"Denies the get_pending command without any pre-configured scope.","commands":{"allow":[],"deny":["get_pending"]}},"deny-is-permission-granted":{"identifier":"deny-is-permission-granted","description":"Denies the is_permission_granted command without any pre-configured scope.","commands":{"allow":[],"deny":["is_permission_granted"]}},"deny-list-channels":{"identifier":"deny-list-channels","description":"Denies the list_channels command without any pre-configured scope.","commands":{"allow":[],"deny":["list_channels"]}},"deny-notify":{"identifier":"deny-notify","description":"Denies the notify command without any pre-configured scope.","commands":{"allow":[],"deny":["notify"]}},"deny-permission-state":{"identifier":"deny-permission-state","description":"Denies the permission_state command without any pre-configured scope.","commands":{"allow":[],"deny":["permission_state"]}},"deny-register-action-types":{"identifier":"deny-register-action-types","description":"Denies the register_action_types command without any pre-configured scope.","commands":{"allow":[],"deny":["register_action_types"]}},"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-active":{"identifier":"deny-remove-active","description":"Denies the remove_active command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_active"]}},"deny-request-permission":{"identifier":"deny-request-permission","description":"Denies the request_permission command without any pre-configured scope.","commands":{"allow":[],"deny":["request_permission"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}}},"permission_sets":{},"global_scope_schema":null},"os":{"default_permission":{"identifier":"default","description":"This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n","permissions":["allow-arch","allow-exe-extension","allow-family","allow-locale","allow-os-type","allow-platform","allow-version"]},"permissions":{"allow-arch":{"identifier":"allow-arch","description":"Enables the arch command without any pre-configured scope.","commands":{"allow":["arch"],"deny":[]}},"allow-exe-extension":{"identifier":"allow-exe-extension","description":"Enables the exe_extension command without any pre-configured scope.","commands":{"allow":["exe_extension"],"deny":[]}},"allow-family":{"identifier":"allow-family","description":"Enables the family command without any pre-configured scope.","commands":{"allow":["family"],"deny":[]}},"allow-hostname":{"identifier":"allow-hostname","description":"Enables the hostname command without any pre-configured scope.","commands":{"allow":["hostname"],"deny":[]}},"allow-locale":{"identifier":"allow-locale","description":"Enables the locale command without any pre-configured scope.","commands":{"allow":["locale"],"deny":[]}},"allow-os-type":{"identifier":"allow-os-type","description":"Enables the os_type command without any pre-configured scope.","commands":{"allow":["os_type"],"deny":[]}},"allow-platform":{"identifier":"allow-platform","description":"Enables the platform command without any pre-configured scope.","commands":{"allow":["platform"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-arch":{"identifier":"deny-arch","description":"Denies the arch command without any pre-configured scope.","commands":{"allow":[],"deny":["arch"]}},"deny-exe-extension":{"identifier":"deny-exe-extension","description":"Denies the exe_extension command without any pre-configured scope.","commands":{"allow":[],"deny":["exe_extension"]}},"deny-family":{"identifier":"deny-family","description":"Denies the family command without any pre-configured scope.","commands":{"allow":[],"deny":["family"]}},"deny-hostname":{"identifier":"deny-hostname","description":"Denies the hostname command without any pre-configured scope.","commands":{"allow":[],"deny":["hostname"]}},"deny-locale":{"identifier":"deny-locale","description":"Denies the locale command without any pre-configured scope.","commands":{"allow":[],"deny":["locale"]}},"deny-os-type":{"identifier":"deny-os-type","description":"Denies the os_type command without any pre-configured scope.","commands":{"allow":[],"deny":["os_type"]}},"deny-platform":{"identifier":"deny-platform","description":"Denies the platform command without any pre-configured scope.","commands":{"allow":[],"deny":["platform"]}},"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},"prevent-default":{"default_permission":{"identifier":"default","description":"Default permissions for the prevent-default plugin","permissions":["allow-keyboard","allow-pointer"]},"permissions":{"allow-keyboard":{"identifier":"allow-keyboard","description":"Enables the keyboard command without any pre-configured scope.","commands":{"allow":["keyboard"],"deny":[]}},"allow-pointer":{"identifier":"allow-pointer","description":"Enables the pointer command without any pre-configured scope.","commands":{"allow":["pointer"],"deny":[]}},"deny-keyboard":{"identifier":"deny-keyboard","description":"Denies the keyboard command without any pre-configured scope.","commands":{"allow":[],"deny":["keyboard"]}},"deny-pointer":{"identifier":"deny-pointer","description":"Denies the pointer command without any pre-configured scope.","commands":{"allow":[],"deny":["pointer"]}}},"permission_sets":{},"global_scope_schema":null},"process":{"default_permission":{"identifier":"default","description":"This permission set configures which\nprocess feeatures are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n","permissions":["allow-exit","allow-restart"]},"permissions":{"allow-exit":{"identifier":"allow-exit","description":"Enables the exit command without any pre-configured scope.","commands":{"allow":["exit"],"deny":[]}},"allow-restart":{"identifier":"allow-restart","description":"Enables the restart command without any pre-configured scope.","commands":{"allow":["restart"],"deny":[]}},"deny-exit":{"identifier":"deny-exit","description":"Denies the exit command without any pre-configured scope.","commands":{"allow":[],"deny":["exit"]}},"deny-restart":{"identifier":"deny-restart","description":"Denies the restart command without any pre-configured scope.","commands":{"allow":[],"deny":["restart"]}}},"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 without any specific\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#","definitions":{"ShellAllowedArg":{"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."},"ShellAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellAllowedArg"},"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 [`ShellAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"A command allowed to be executed by the webview API.","properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellAllowedArgs"}],"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`, `$APP`, `$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"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["args","cmd","name","sidecar"],"title":"Entry","type":"object"}},"theme":{"default_permission":null,"permissions":{"allow-get-theme":{"identifier":"allow-get-theme","description":"Enables the get_theme command without any pre-configured scope.","commands":{"allow":["get_theme"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"deny-get-theme":{"identifier":"deny-get-theme","description":"Denies the get_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["get_theme"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}}},"permission_sets":{},"global_scope_schema":null},"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},"upload":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the upload plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-upload","allow-download"]},"permissions":{"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-upload":{"identifier":"allow-upload","description":"Enables the upload command without any pre-configured scope.","commands":{"allow":["upload"],"deny":[]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-upload":{"identifier":"deny-upload","description":"Denies the upload command without any pre-configured scope.","commands":{"allow":[],"deny":["upload"]}}},"permission_sets":{},"global_scope_schema":null},"window-state":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the window state plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-filename","allow-restore-state","allow-save-window-state"]},"permissions":{"allow-filename":{"identifier":"allow-filename","description":"Enables the filename command without any pre-configured scope.","commands":{"allow":["filename"],"deny":[]}},"allow-restore-state":{"identifier":"allow-restore-state","description":"Enables the restore_state command without any pre-configured scope.","commands":{"allow":["restore_state"],"deny":[]}},"allow-save-window-state":{"identifier":"allow-save-window-state","description":"Enables the save_window_state command without any pre-configured scope.","commands":{"allow":["save_window_state"],"deny":[]}},"deny-filename":{"identifier":"deny-filename","description":"Denies the filename command without any pre-configured scope.","commands":{"allow":[],"deny":["filename"]}},"deny-restore-state":{"identifier":"deny-restore-state","description":"Denies the restore_state command without any pre-configured scope.","commands":{"allow":[],"deny":["restore_state"]}},"deny-save-window-state":{"identifier":"deny-save-window-state","description":"Denies the save_window_state command without any pre-configured scope.","commands":{"allow":[],"deny":["save_window_state"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file +{"clipboard-manager":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n","permissions":[]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-read-image":{"identifier":"allow-read-image","description":"Enables the read_image command without any pre-configured scope.","commands":{"allow":["read_image"],"deny":[]}},"allow-read-text":{"identifier":"allow-read-text","description":"Enables the read_text command without any pre-configured scope.","commands":{"allow":["read_text"],"deny":[]}},"allow-write-html":{"identifier":"allow-write-html","description":"Enables the write_html command without any pre-configured scope.","commands":{"allow":["write_html"],"deny":[]}},"allow-write-image":{"identifier":"allow-write-image","description":"Enables the write_image command without any pre-configured scope.","commands":{"allow":["write_image"],"deny":[]}},"allow-write-text":{"identifier":"allow-write-text","description":"Enables the write_text command without any pre-configured scope.","commands":{"allow":["write_text"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-read-image":{"identifier":"deny-read-image","description":"Denies the read_image command without any pre-configured scope.","commands":{"allow":[],"deny":["read_image"]}},"deny-read-text":{"identifier":"deny-read-text","description":"Denies the read_text command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text"]}},"deny-write-html":{"identifier":"deny-write-html","description":"Denies the write_html command without any pre-configured scope.","commands":{"allow":[],"deny":["write_html"]}},"deny-write-image":{"identifier":"deny-write-image","description":"Denies the write_image command without any pre-configured scope.","commands":{"allow":[],"deny":["write_image"]}},"deny-write-text":{"identifier":"deny-write-text","description":"Denies the write_text command without any pre-configured scope.","commands":{"allow":[],"deny":["write_text"]}}},"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"]},"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-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-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"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-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-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"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.","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.","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.","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.","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.","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.","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-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-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-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-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-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-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"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-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-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-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"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-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-internal-toggle-maximize"]},"permissions":{"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-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-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-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-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-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"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-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-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-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-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-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-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-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-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-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"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-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-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-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},"decorum":{"default_permission":null,"permissions":{"allow-show-snap-overlay":{"identifier":"allow-show-snap-overlay","description":"Enables the show_snap_overlay command without any pre-configured scope.","commands":{"allow":["show_snap_overlay"],"deny":[]}},"deny-show-snap-overlay":{"identifier":"deny-show-snap-overlay","description":"Denies the show_snap_overlay command without any pre-configured scope.","commands":{"allow":[],"deny":["show_snap_overlay"]}}},"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-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"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.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"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\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"],"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-stat":{"identifier":"allow-stat","description":"Enables the stat command without any pre-configured scope.","commands":{"allow":["stat"],"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"],"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"],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"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-stat":{"identifier":"deny-stat","description":"Denies the stat command without any pre-configured scope.","commands":{"allow":[],"deny":["stat"]}},"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"],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG/**"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE/**"},{"path":"$APPLOG/**"}]}},"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"],"deny":[]}},"scope":{"identifier":"scope","description":"An empty permission you can use to modify the global scope.","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 `$APP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the `$APP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete `$APP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APP/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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/*"}]}},"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/**"}]}},"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 `$APP` folder, 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 `$APP` folder, 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 `$APP` folder.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete `$APP` folder, 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 `$APP` folder.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete `$APP` folder, 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":"FS scope path.","type":"string"},{"properties":{"path":{"description":"FS scope path.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"http":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\nfetch operations are available from the http plugin.\n\nThis enables all fetch operations but does not\nallow explicitly any origins to be fetched. This needs to\nbe manually configured before usage.\n\n#### Granted Permissions\n\nAll fetch operations are enabled.\n\n","permissions":["allow-fetch","allow-fetch-cancel","allow-fetch-read-body","allow-fetch-send"]},"permissions":{"allow-fetch":{"identifier":"allow-fetch","description":"Enables the fetch command without any pre-configured scope.","commands":{"allow":["fetch"],"deny":[]}},"allow-fetch-cancel":{"identifier":"allow-fetch-cancel","description":"Enables the fetch_cancel command without any pre-configured scope.","commands":{"allow":["fetch_cancel"],"deny":[]}},"allow-fetch-read-body":{"identifier":"allow-fetch-read-body","description":"Enables the fetch_read_body command without any pre-configured scope.","commands":{"allow":["fetch_read_body"],"deny":[]}},"allow-fetch-send":{"identifier":"allow-fetch-send","description":"Enables the fetch_send command without any pre-configured scope.","commands":{"allow":["fetch_send"],"deny":[]}},"deny-fetch":{"identifier":"deny-fetch","description":"Denies the fetch command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch"]}},"deny-fetch-cancel":{"identifier":"deny-fetch-cancel","description":"Denies the fetch_cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_cancel"]}},"deny-fetch-read-body":{"identifier":"deny-fetch-read-body","description":"Denies the fetch_read_body command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_read_body"]}},"deny-fetch-send":{"identifier":"deny-fetch-send","description":"Denies the fetch_send command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_send"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"},{"properties":{"url":{"description":"A URL that can be accessed by the webview when using the HTTP APIs. Wildcards can be used following the URL pattern standard.\n\nSee [the URL Pattern spec](https://urlpattern.spec.whatwg.org/) for more information.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin on port 443\n\n- \"https://*:*\" : allows all HTTPS origin on any port\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"}],"description":"HTTP scope entry.","title":"HttpScopeEntry"}},"notification":{"default_permission":{"identifier":"default","description":"This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n","permissions":["allow-is-permission-granted","allow-request-permission","allow-notify","allow-register-action-types","allow-register-listener","allow-cancel","allow-get-pending","allow-remove-active","allow-get-active","allow-check-permissions","allow-show","allow-batch","allow-list-channels","allow-delete-channel","allow-create-channel","allow-permission-state"]},"permissions":{"allow-batch":{"identifier":"allow-batch","description":"Enables the batch command without any pre-configured scope.","commands":{"allow":["batch"],"deny":[]}},"allow-cancel":{"identifier":"allow-cancel","description":"Enables the cancel command without any pre-configured scope.","commands":{"allow":["cancel"],"deny":[]}},"allow-check-permissions":{"identifier":"allow-check-permissions","description":"Enables the check_permissions command without any pre-configured scope.","commands":{"allow":["check_permissions"],"deny":[]}},"allow-create-channel":{"identifier":"allow-create-channel","description":"Enables the create_channel command without any pre-configured scope.","commands":{"allow":["create_channel"],"deny":[]}},"allow-delete-channel":{"identifier":"allow-delete-channel","description":"Enables the delete_channel command without any pre-configured scope.","commands":{"allow":["delete_channel"],"deny":[]}},"allow-get-active":{"identifier":"allow-get-active","description":"Enables the get_active command without any pre-configured scope.","commands":{"allow":["get_active"],"deny":[]}},"allow-get-pending":{"identifier":"allow-get-pending","description":"Enables the get_pending command without any pre-configured scope.","commands":{"allow":["get_pending"],"deny":[]}},"allow-is-permission-granted":{"identifier":"allow-is-permission-granted","description":"Enables the is_permission_granted command without any pre-configured scope.","commands":{"allow":["is_permission_granted"],"deny":[]}},"allow-list-channels":{"identifier":"allow-list-channels","description":"Enables the list_channels command without any pre-configured scope.","commands":{"allow":["list_channels"],"deny":[]}},"allow-notify":{"identifier":"allow-notify","description":"Enables the notify command without any pre-configured scope.","commands":{"allow":["notify"],"deny":[]}},"allow-permission-state":{"identifier":"allow-permission-state","description":"Enables the permission_state command without any pre-configured scope.","commands":{"allow":["permission_state"],"deny":[]}},"allow-register-action-types":{"identifier":"allow-register-action-types","description":"Enables the register_action_types command without any pre-configured scope.","commands":{"allow":["register_action_types"],"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-active":{"identifier":"allow-remove-active","description":"Enables the remove_active command without any pre-configured scope.","commands":{"allow":["remove_active"],"deny":[]}},"allow-request-permission":{"identifier":"allow-request-permission","description":"Enables the request_permission command without any pre-configured scope.","commands":{"allow":["request_permission"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"deny-batch":{"identifier":"deny-batch","description":"Denies the batch command without any pre-configured scope.","commands":{"allow":[],"deny":["batch"]}},"deny-cancel":{"identifier":"deny-cancel","description":"Denies the cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["cancel"]}},"deny-check-permissions":{"identifier":"deny-check-permissions","description":"Denies the check_permissions command without any pre-configured scope.","commands":{"allow":[],"deny":["check_permissions"]}},"deny-create-channel":{"identifier":"deny-create-channel","description":"Denies the create_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["create_channel"]}},"deny-delete-channel":{"identifier":"deny-delete-channel","description":"Denies the delete_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["delete_channel"]}},"deny-get-active":{"identifier":"deny-get-active","description":"Denies the get_active command without any pre-configured scope.","commands":{"allow":[],"deny":["get_active"]}},"deny-get-pending":{"identifier":"deny-get-pending","description":"Denies the get_pending command without any pre-configured scope.","commands":{"allow":[],"deny":["get_pending"]}},"deny-is-permission-granted":{"identifier":"deny-is-permission-granted","description":"Denies the is_permission_granted command without any pre-configured scope.","commands":{"allow":[],"deny":["is_permission_granted"]}},"deny-list-channels":{"identifier":"deny-list-channels","description":"Denies the list_channels command without any pre-configured scope.","commands":{"allow":[],"deny":["list_channels"]}},"deny-notify":{"identifier":"deny-notify","description":"Denies the notify command without any pre-configured scope.","commands":{"allow":[],"deny":["notify"]}},"deny-permission-state":{"identifier":"deny-permission-state","description":"Denies the permission_state command without any pre-configured scope.","commands":{"allow":[],"deny":["permission_state"]}},"deny-register-action-types":{"identifier":"deny-register-action-types","description":"Denies the register_action_types command without any pre-configured scope.","commands":{"allow":[],"deny":["register_action_types"]}},"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-active":{"identifier":"deny-remove-active","description":"Denies the remove_active command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_active"]}},"deny-request-permission":{"identifier":"deny-request-permission","description":"Denies the request_permission command without any pre-configured scope.","commands":{"allow":[],"deny":["request_permission"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}}},"permission_sets":{},"global_scope_schema":null},"os":{"default_permission":{"identifier":"default","description":"This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n","permissions":["allow-arch","allow-exe-extension","allow-family","allow-locale","allow-os-type","allow-platform","allow-version"]},"permissions":{"allow-arch":{"identifier":"allow-arch","description":"Enables the arch command without any pre-configured scope.","commands":{"allow":["arch"],"deny":[]}},"allow-exe-extension":{"identifier":"allow-exe-extension","description":"Enables the exe_extension command without any pre-configured scope.","commands":{"allow":["exe_extension"],"deny":[]}},"allow-family":{"identifier":"allow-family","description":"Enables the family command without any pre-configured scope.","commands":{"allow":["family"],"deny":[]}},"allow-hostname":{"identifier":"allow-hostname","description":"Enables the hostname command without any pre-configured scope.","commands":{"allow":["hostname"],"deny":[]}},"allow-locale":{"identifier":"allow-locale","description":"Enables the locale command without any pre-configured scope.","commands":{"allow":["locale"],"deny":[]}},"allow-os-type":{"identifier":"allow-os-type","description":"Enables the os_type command without any pre-configured scope.","commands":{"allow":["os_type"],"deny":[]}},"allow-platform":{"identifier":"allow-platform","description":"Enables the platform command without any pre-configured scope.","commands":{"allow":["platform"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-arch":{"identifier":"deny-arch","description":"Denies the arch command without any pre-configured scope.","commands":{"allow":[],"deny":["arch"]}},"deny-exe-extension":{"identifier":"deny-exe-extension","description":"Denies the exe_extension command without any pre-configured scope.","commands":{"allow":[],"deny":["exe_extension"]}},"deny-family":{"identifier":"deny-family","description":"Denies the family command without any pre-configured scope.","commands":{"allow":[],"deny":["family"]}},"deny-hostname":{"identifier":"deny-hostname","description":"Denies the hostname command without any pre-configured scope.","commands":{"allow":[],"deny":["hostname"]}},"deny-locale":{"identifier":"deny-locale","description":"Denies the locale command without any pre-configured scope.","commands":{"allow":[],"deny":["locale"]}},"deny-os-type":{"identifier":"deny-os-type","description":"Denies the os_type command without any pre-configured scope.","commands":{"allow":[],"deny":["os_type"]}},"deny-platform":{"identifier":"deny-platform","description":"Denies the platform command without any pre-configured scope.","commands":{"allow":[],"deny":["platform"]}},"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},"prevent-default":{"default_permission":{"identifier":"default","description":"Default permissions for the prevent-default plugin","permissions":["allow-keyboard","allow-pointer"]},"permissions":{"allow-keyboard":{"identifier":"allow-keyboard","description":"Enables the keyboard command without any pre-configured scope.","commands":{"allow":["keyboard"],"deny":[]}},"allow-pointer":{"identifier":"allow-pointer","description":"Enables the pointer command without any pre-configured scope.","commands":{"allow":["pointer"],"deny":[]}},"deny-keyboard":{"identifier":"deny-keyboard","description":"Denies the keyboard command without any pre-configured scope.","commands":{"allow":[],"deny":["keyboard"]}},"deny-pointer":{"identifier":"deny-pointer","description":"Denies the pointer command without any pre-configured scope.","commands":{"allow":[],"deny":["pointer"]}}},"permission_sets":{},"global_scope_schema":null},"process":{"default_permission":{"identifier":"default","description":"This permission set configures which\nprocess feeatures are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n","permissions":["allow-exit","allow-restart"]},"permissions":{"allow-exit":{"identifier":"allow-exit","description":"Enables the exit command without any pre-configured scope.","commands":{"allow":["exit"],"deny":[]}},"allow-restart":{"identifier":"allow-restart","description":"Enables the restart command without any pre-configured scope.","commands":{"allow":["restart"],"deny":[]}},"deny-exit":{"identifier":"deny-exit","description":"Denies the exit command without any pre-configured scope.","commands":{"allow":[],"deny":["exit"]}},"deny-restart":{"identifier":"deny-restart","description":"Denies the restart command without any pre-configured scope.","commands":{"allow":[],"deny":["restart"]}}},"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 without any specific\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#","definitions":{"ShellAllowedArg":{"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."},"ShellAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellAllowedArg"},"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 [`ShellAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"A command allowed to be executed by the webview API.","properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellAllowedArgs"}],"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`, `$APP`, `$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"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["args","cmd","name","sidecar"],"title":"Entry","type":"object"}},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-clear","allow-delete","allow-entries","allow-get","allow-has","allow-keys","allow-length","allow-load","allow-reset","allow-save","allow-set","allow-values"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null},"theme":{"default_permission":null,"permissions":{"allow-get-theme":{"identifier":"allow-get-theme","description":"Enables the get_theme command without any pre-configured scope.","commands":{"allow":["get_theme"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"deny-get-theme":{"identifier":"deny-get-theme","description":"Denies the get_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["get_theme"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}}},"permission_sets":{},"global_scope_schema":null},"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},"upload":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the upload plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-upload","allow-download"]},"permissions":{"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-upload":{"identifier":"allow-upload","description":"Enables the upload command without any pre-configured scope.","commands":{"allow":["upload"],"deny":[]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-upload":{"identifier":"deny-upload","description":"Denies the upload command without any pre-configured scope.","commands":{"allow":[],"deny":["upload"]}}},"permission_sets":{},"global_scope_schema":null},"window-state":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the window state plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-filename","allow-restore-state","allow-save-window-state"]},"permissions":{"allow-filename":{"identifier":"allow-filename","description":"Enables the filename command without any pre-configured scope.","commands":{"allow":["filename"],"deny":[]}},"allow-restore-state":{"identifier":"allow-restore-state","description":"Enables the restore_state command without any pre-configured scope.","commands":{"allow":["restore_state"],"deny":[]}},"allow-save-window-state":{"identifier":"allow-save-window-state","description":"Enables the save_window_state command without any pre-configured scope.","commands":{"allow":["save_window_state"],"deny":[]}},"deny-filename":{"identifier":"deny-filename","description":"Denies the filename command without any pre-configured scope.","commands":{"allow":[],"deny":["filename"]}},"deny-restore-state":{"identifier":"deny-restore-state","description":"Denies the restore_state command without any pre-configured scope.","commands":{"allow":[],"deny":["restore_state"]}},"deny-save-window-state":{"identifier":"deny-save-window-state","description":"Denies the save_window_state command without any pre-configured scope.","commands":{"allow":[],"deny":["save_window_state"]}}},"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 ffda85a5..0ab1d065 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","panel","settings","search-*","zap-*","event-*","user-*","editor-*"],"permissions":["core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","os:allow-os-type","updater:default","updater:allow-check","updater:allow-download-and-install","core:window:allow-create","core:window:allow-close","core:window:allow-destroy","core:window:allow-set-focus","core:window:allow-center","core:window:allow-minimize","core:window:allow-maximize","core:window:allow-set-size","core:window:allow-set-focus","core:window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-set-webview-size","core:webview:allow-set-webview-position","core:webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","process:allow-exit","fs:allow-read-file","theme:allow-set-theme","theme:allow-get-theme","core:menu:allow-new","core:menu:allow-popup","shell:allow-open","prevent-default:default",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}} \ No newline at end of file +{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","panel","settings","search-*","zap-*","event-*","user-*","editor-*"],"permissions":["core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","os:allow-os-type","updater:default","updater:allow-check","updater:allow-download-and-install","core:window:allow-create","core:window:allow-close","core:window:allow-destroy","core:window:allow-set-focus","core:window:allow-center","core:window:allow-minimize","core:window:allow-maximize","core:window:allow-set-size","core:window:allow-set-focus","core:window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-set-webview-size","core:webview:allow-set-webview-position","core:webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","process:allow-exit","fs:allow-read-file","theme:allow-set-theme","theme:allow-get-theme","core:menu:allow-new","core:menu:allow-popup","shell:allow-open","store:allow-get","store:allow-set","store:allow-delete","prevent-default:default",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["macOS","windows"]}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/desktop-schema.json b/src-tauri/gen/schemas/desktop-schema.json index d60bf3ed..1a966ca7 100644 --- a/src-tauri/gen/schemas/desktop-schema.json +++ b/src-tauri/gen/schemas/desktop-schema.json @@ -7201,6 +7201,181 @@ "shell:deny-stdin-write" ] }, + { + "description": "store:default -> This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n", + "type": "string", + "enum": [ + "store:default" + ] + }, + { + "description": "store:allow-clear -> Enables the clear command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-clear" + ] + }, + { + "description": "store:allow-delete -> Enables the delete command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-delete" + ] + }, + { + "description": "store:allow-entries -> Enables the entries command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-entries" + ] + }, + { + "description": "store:allow-get -> Enables the get command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-get" + ] + }, + { + "description": "store:allow-has -> Enables the has command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-has" + ] + }, + { + "description": "store:allow-keys -> Enables the keys command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-keys" + ] + }, + { + "description": "store:allow-length -> Enables the length command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-length" + ] + }, + { + "description": "store:allow-load -> Enables the load command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-load" + ] + }, + { + "description": "store:allow-reset -> Enables the reset command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-reset" + ] + }, + { + "description": "store:allow-save -> Enables the save command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-save" + ] + }, + { + "description": "store:allow-set -> Enables the set command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-set" + ] + }, + { + "description": "store:allow-values -> Enables the values command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-values" + ] + }, + { + "description": "store:deny-clear -> Denies the clear command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-clear" + ] + }, + { + "description": "store:deny-delete -> Denies the delete command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-delete" + ] + }, + { + "description": "store:deny-entries -> Denies the entries command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-entries" + ] + }, + { + "description": "store:deny-get -> Denies the get command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-get" + ] + }, + { + "description": "store:deny-has -> Denies the has command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-has" + ] + }, + { + "description": "store:deny-keys -> Denies the keys command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-keys" + ] + }, + { + "description": "store:deny-length -> Denies the length command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-length" + ] + }, + { + "description": "store:deny-load -> Denies the load command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-load" + ] + }, + { + "description": "store:deny-reset -> Denies the reset command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-reset" + ] + }, + { + "description": "store:deny-save -> Denies the save command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-save" + ] + }, + { + "description": "store:deny-set -> Denies the set command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-set" + ] + }, + { + "description": "store:deny-values -> Denies the values command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-values" + ] + }, { "type": "string", "enum": [ diff --git a/src-tauri/gen/schemas/macOS-schema.json b/src-tauri/gen/schemas/macOS-schema.json index d60bf3ed..1a966ca7 100644 --- a/src-tauri/gen/schemas/macOS-schema.json +++ b/src-tauri/gen/schemas/macOS-schema.json @@ -7201,6 +7201,181 @@ "shell:deny-stdin-write" ] }, + { + "description": "store:default -> This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n", + "type": "string", + "enum": [ + "store:default" + ] + }, + { + "description": "store:allow-clear -> Enables the clear command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-clear" + ] + }, + { + "description": "store:allow-delete -> Enables the delete command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-delete" + ] + }, + { + "description": "store:allow-entries -> Enables the entries command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-entries" + ] + }, + { + "description": "store:allow-get -> Enables the get command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-get" + ] + }, + { + "description": "store:allow-has -> Enables the has command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-has" + ] + }, + { + "description": "store:allow-keys -> Enables the keys command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-keys" + ] + }, + { + "description": "store:allow-length -> Enables the length command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-length" + ] + }, + { + "description": "store:allow-load -> Enables the load command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-load" + ] + }, + { + "description": "store:allow-reset -> Enables the reset command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-reset" + ] + }, + { + "description": "store:allow-save -> Enables the save command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-save" + ] + }, + { + "description": "store:allow-set -> Enables the set command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-set" + ] + }, + { + "description": "store:allow-values -> Enables the values command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:allow-values" + ] + }, + { + "description": "store:deny-clear -> Denies the clear command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-clear" + ] + }, + { + "description": "store:deny-delete -> Denies the delete command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-delete" + ] + }, + { + "description": "store:deny-entries -> Denies the entries command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-entries" + ] + }, + { + "description": "store:deny-get -> Denies the get command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-get" + ] + }, + { + "description": "store:deny-has -> Denies the has command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-has" + ] + }, + { + "description": "store:deny-keys -> Denies the keys command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-keys" + ] + }, + { + "description": "store:deny-length -> Denies the length command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-length" + ] + }, + { + "description": "store:deny-load -> Denies the load command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-load" + ] + }, + { + "description": "store:deny-reset -> Denies the reset command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-reset" + ] + }, + { + "description": "store:deny-save -> Denies the save command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-save" + ] + }, + { + "description": "store:deny-set -> Denies the set command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-set" + ] + }, + { + "description": "store:deny-values -> Denies the values command without any pre-configured scope.", + "type": "string", + "enum": [ + "store:deny-values" + ] + }, { "type": "string", "enum": [ diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png index 0f9a396b..e350739d 100644 Binary files a/src-tauri/icons/128x128.png and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png index d0f1daab..7e2a9c56 100644 Binary files a/src-tauri/icons/128x128@2x.png and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png index 75775b77..03b7a771 100644 Binary files a/src-tauri/icons/32x32.png and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png index 4e974be2..49792393 100644 Binary files a/src-tauri/icons/Square107x107Logo.png and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png index 3ad3f89a..c37f80ea 100644 Binary files a/src-tauri/icons/Square142x142Logo.png and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png index 48e1eddd..89506170 100644 Binary files a/src-tauri/icons/Square150x150Logo.png and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png index 0826f7c8..98b3413d 100644 Binary files a/src-tauri/icons/Square284x284Logo.png and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png index 32558a86..b67ecbff 100644 Binary files a/src-tauri/icons/Square30x30Logo.png and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png index 2e8c7d1b..756eb301 100644 Binary files a/src-tauri/icons/Square310x310Logo.png and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png index 49597838..e3204d97 100644 Binary files a/src-tauri/icons/Square44x44Logo.png and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png index 2121f963..2eec4806 100644 Binary files a/src-tauri/icons/Square71x71Logo.png and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png index a6fcbe67..c5ce9627 100644 Binary files a/src-tauri/icons/Square89x89Logo.png and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png index 83f989a5..8d49bf6a 100644 Binary files a/src-tauri/icons/StoreLogo.png and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png index 575332d6..c326c6d9 100644 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png index 86346447..bb739c6a 100644 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png index 575332d6..c326c6d9 100644 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png index fa361e3c..cb07e1e6 100644 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png index 8711475c..78eb7ca6 100644 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png index fa361e3c..cb07e1e6 100644 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png index f946d16a..f87ae8a6 100644 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png index 03b18259..4ee33824 100644 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png index f946d16a..f87ae8a6 100644 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png index ada9b6fc..0028ffcc 100644 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png index 45c60183..ecf07a72 100644 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png index ada9b6fc..0028ffcc 100644 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png index a173158c..b5ae1b66 100644 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png index 75829f60..c472850f 100644 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png index a173158c..b5ae1b66 100644 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns index 2e376a52..9fc55d12 100644 Binary files a/src-tauri/icons/icon.icns and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico index 18619806..1d0974b6 100644 Binary files a/src-tauri/icons/icon.ico and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png index 3094cb8e..63dc36de 100644 Binary files a/src-tauri/icons/icon.png and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png index 35ae8665..628f3d5f 100644 Binary files a/src-tauri/icons/ios/AppIcon-20x20@1x.png and b/src-tauri/icons/ios/AppIcon-20x20@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png index e4139008..edf739c8 100644 Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png index e4139008..edf739c8 100644 Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x.png and b/src-tauri/icons/ios/AppIcon-20x20@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png index 2a8c7c0b..8333a05e 100644 Binary files a/src-tauri/icons/ios/AppIcon-20x20@3x.png and b/src-tauri/icons/ios/AppIcon-20x20@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@1x.png b/src-tauri/icons/ios/AppIcon-29x29@1x.png index 627498f9..ea70093c 100644 Binary files a/src-tauri/icons/ios/AppIcon-29x29@1x.png and b/src-tauri/icons/ios/AppIcon-29x29@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png index 54d1fbdc..56d598e4 100644 Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x.png b/src-tauri/icons/ios/AppIcon-29x29@2x.png index 54d1fbdc..56d598e4 100644 Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x.png and b/src-tauri/icons/ios/AppIcon-29x29@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@3x.png b/src-tauri/icons/ios/AppIcon-29x29@3x.png index 5fe14930..ad378bd6 100644 Binary files a/src-tauri/icons/ios/AppIcon-29x29@3x.png and b/src-tauri/icons/ios/AppIcon-29x29@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png index e4139008..edf739c8 100644 Binary files a/src-tauri/icons/ios/AppIcon-40x40@1x.png and b/src-tauri/icons/ios/AppIcon-40x40@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png index d7f717b7..f8c0e414 100644 Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x.png b/src-tauri/icons/ios/AppIcon-40x40@2x.png index d7f717b7..f8c0e414 100644 Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x.png and b/src-tauri/icons/ios/AppIcon-40x40@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@3x.png b/src-tauri/icons/ios/AppIcon-40x40@3x.png index a06d2484..ea58b4be 100644 Binary files a/src-tauri/icons/ios/AppIcon-40x40@3x.png and b/src-tauri/icons/ios/AppIcon-40x40@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png index fd102150..d48cfe8b 100644 Binary files a/src-tauri/icons/ios/AppIcon-512@2x.png and b/src-tauri/icons/ios/AppIcon-512@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@2x.png b/src-tauri/icons/ios/AppIcon-60x60@2x.png index a06d2484..ea58b4be 100644 Binary files a/src-tauri/icons/ios/AppIcon-60x60@2x.png and b/src-tauri/icons/ios/AppIcon-60x60@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png index 8df15775..fba5f8db 100644 Binary files a/src-tauri/icons/ios/AppIcon-60x60@3x.png and b/src-tauri/icons/ios/AppIcon-60x60@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png index 39c122e4..0eb02242 100644 Binary files a/src-tauri/icons/ios/AppIcon-76x76@1x.png and b/src-tauri/icons/ios/AppIcon-76x76@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@2x.png b/src-tauri/icons/ios/AppIcon-76x76@2x.png index 2a901cdb..65b7666b 100644 Binary files a/src-tauri/icons/ios/AppIcon-76x76@2x.png and b/src-tauri/icons/ios/AppIcon-76x76@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png index 0c7f21dc..a4e4d95b 100644 Binary files a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/src-tauri/icons/tray.png b/src-tauri/icons/tray.png deleted file mode 100644 index 9317426e..00000000 Binary files a/src-tauri/icons/tray.png and /dev/null differ diff --git a/src-tauri/resources/columns.json b/src-tauri/resources/columns.json new file mode 100644 index 00000000..d0f44f64 --- /dev/null +++ b/src-tauri/resources/columns.json @@ -0,0 +1,83 @@ +[ + { + "default": true, + "official": true, + "label": "onboarding", + "name": "Onboarding", + "description": "Tips for Mastering Lume.", + "url": "/columns/onboarding", + "picture": "" + }, + { + "default": true, + "official": true, + "label": "columns_gallery", + "name": "Columns Gallery", + "description": "Expand your experiences.", + "url": "/columns/gallery", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "local_feeds", + "name": "Local Feeds", + "description": "All notes from your follows.", + "url": "/columns/newsfeed", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "notification", + "name": "Notification", + "description": "All things around you.", + "url": "/columns/notification", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "search", + "name": "Search", + "description": "Find anything.", + "url": "/columns/search", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "stories", + "name": "Stories", + "description": "Keep up to date with your follows.", + "url": "/columns/stories", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "global_feeds", + "name": "Global Feeds", + "description": "Discover all global notes.", + "url": "/columns/global", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "group_feeds", + "name": "Group", + "description": "Custom feeds for group of people.", + "url": "/columns/group", + "picture": "" + }, + { + "default": false, + "official": true, + "label": "trending", + "name": "Trending", + "description": "Discover all trending notes.", + "url": "/columns/trending", + "picture": "" + } +] diff --git a/src-tauri/resources/official_columns.json b/src-tauri/resources/official_columns.json deleted file mode 100644 index 316c4f2a..00000000 --- a/src-tauri/resources/official_columns.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "label": "lZfXLFgPPR4NNrgjlWDxn", - "name": "Local Feeds", - "content": "/newsfeed", - "cover": "/newsfeed.png", - "coverRetina": "/newsfeed@2x.png" - }, - { - "label": "GLFm44za8rhJDP04LMr3M", - "name": "Global Feeds", - "content": "/global", - "cover": "/global.png", - "coverRetina": "/global@2x.png" - }, - { - "label": "fve9fk2fVyFWORPBkjd79", - "name": "Group Feeds", - "content": "/group", - "cover": "/group.png", - "coverRetina": "/group@2x.png" - }, - { - "label": "rRtguZwIpd5G8Wt54OTb7", - "name": "Topic", - "content": "/topic", - "cover": "/foryou.png", - "coverRetina": "/foryou@2x.png" - }, - { - "label": "gxtcIbgD8YNPbeI5o92I8", - "name": "Trending", - "content": "/trending/notes", - "cover": "/trending.png", - "coverRetina": "/trending@2x.png" - } -] diff --git a/src-tauri/resources/relays.txt b/src-tauri/resources/relays.txt index 07914bf8..103a70b0 100644 --- a/src-tauri/resources/relays.txt +++ b/src-tauri/resources/relays.txt @@ -1,2 +1,4 @@ wss://relay.damus.io, wss://relay.nostr.net, +wss://purplepag.es/, +wss://directory.yabu.me/, diff --git a/src-tauri/resources/system_columns.json b/src-tauri/resources/system_columns.json deleted file mode 100644 index eedac602..00000000 --- a/src-tauri/resources/system_columns.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - { "label": "onboarding", "name": "Onboarding", "content": "/onboarding" }, - { "label": "lume_newsfeed", "name": "Newsfeed", "content": "/newsfeed" }, - { "label": "lume_topic", "name": "Topic", "content": "/topic" } -] diff --git a/src-tauri/src/commands/account.rs b/src-tauri/src/commands/account.rs index d33fb4a9..cc6cdcf2 100644 --- a/src-tauri/src/commands/account.rs +++ b/src-tauri/src/commands/account.rs @@ -4,14 +4,11 @@ use nostr_sdk::prelude::*; use serde::{Deserialize, Serialize}; use specta::Type; use std::{collections::HashSet, str::FromStr, time::Duration}; -use tauri::{Emitter, EventTarget, Manager, State}; -use tauri_plugin_notification::NotificationExt; +use tauri::{Emitter, Manager, State}; -// #[cfg(target_os = "macos")] -// use crate::commands::tray::create_tray_panel; use crate::{ - common::{get_user_settings, init_nip65, parse_event}, - Nostr, RichEvent, NEWSFEED_NEG_LIMIT, NOTIFICATION_NEG_LIMIT, + common::{get_user_settings, init_nip65}, + Nostr, NEWSFEED_NEG_LIMIT, NOTIFICATION_NEG_LIMIT, NOTIFICATION_SUB_ID, }; #[derive(Debug, Clone, Serialize, Deserialize, Type)] @@ -165,6 +162,37 @@ pub async fn connect_account(uri: String, state: State<'_, Nostr>) -> Result Result<(), String> { + let secret_key = SecretKey::from_bech32(key).map_err(|err| err.to_string())?; + let keys = Keys::new(secret_key.clone()); + let npub = keys.public_key().to_bech32().unwrap(); + + let enc = EncryptedSecretKey::new(&secret_key, password, 16, KeySecurity::Medium) + .map_err(|err| err.to_string())?; + let enc_bech32 = enc.to_bech32().map_err(|err| err.to_string())?; + + let keyring = Entry::new("Lume Secret Storage", &npub).map_err(|e| e.to_string())?; + let account = Account { + password: enc_bech32, + nostr_connect: None, + }; + let j = serde_json::to_string(&account).map_err(|e| e.to_string())?; + let _ = keyring.set_password(&j); + + Ok(()) +} + +#[tauri::command] +#[specta::specta] +pub fn get_private_key(id: String) -> Result { + let keyring = Entry::new("Lume Secret Storage", &id).map_err(|e| e.to_string())?; + let password = keyring.get_password().map_err(|e| e.to_string())?; + + Ok(password) +} + #[tauri::command] #[specta::specta] pub fn delete_account(id: String) -> Result<(), String> { @@ -180,9 +208,8 @@ pub async fn login( account: String, password: String, state: State<'_, Nostr>, - app: tauri::AppHandle, + handle: tauri::AppHandle, ) -> Result { - let handle = app.clone(); let client = &state.client; let keyring = Entry::new("Lume Secret Storage", &account).map_err(|e| e.to_string())?; @@ -229,77 +256,66 @@ pub async fn login( // Connect to user's relay (NIP-65) init_nip65(client).await; - // Create tray (macOS) - // #[cfg(target_os = "macos")] - // create_tray_panel(&public_key.to_bech32().unwrap(), &handle); - // Get user's contact list if let Ok(contacts) = client.get_contact_list(Some(Duration::from_secs(5))).await { - *state.contact_list.lock().unwrap() = contacts + let mut contacts_state = state.contact_list.lock().await; + *contacts_state = contacts; }; // Get user's settings if let Ok(settings) = get_user_settings(client).await { - *state.settings.lock().unwrap() = settings + let mut settings_state = state.settings.lock().await; + *settings_state = settings; }; tauri::async_runtime::spawn(async move { - let window = handle.get_window("main").unwrap(); - - let state = window.state::(); + let state = handle.state::(); let client = &state.client; - let contact_list = state.contact_list.lock().unwrap().clone(); + let contact_list = state.contact_list.lock().await; let signer = client.signer().await.unwrap(); let public_key = signer.public_key().await.unwrap(); + let notification_id = SubscriptionId::new(NOTIFICATION_SUB_ID); + if !contact_list.is_empty() { - let authors: Vec = contact_list.into_iter().map(|f| f.public_key).collect(); + let authors: Vec = contact_list.iter().map(|f| f.public_key).collect(); + let sync = Filter::new() + .authors(authors.clone()) + .kinds(vec![Kind::TextNote, Kind::Repost]) + .limit(NEWSFEED_NEG_LIMIT); - match client - .reconcile( - Filter::new() - .authors(authors) - .kinds(vec![Kind::TextNote, Kind::Repost]) - .limit(NEWSFEED_NEG_LIMIT), - NegentropyOptions::default(), - ) + if client + .reconcile(sync, NegentropyOptions::default()) .await + .is_ok() { - Ok(_) => { - if handle.emit_to(EventTarget::Any, "synced", true).is_err() { - println!("Emit event failed.") - } - } - Err(_) => println!("Sync newsfeed failed."), + handle.emit("newsfeed_synchronized", ()).unwrap(); } }; - match client - .reconcile( - Filter::new() - .pubkey(public_key) - .kinds(vec![ - Kind::TextNote, - Kind::Repost, - Kind::Reaction, - Kind::ZapReceipt, - ]) - .limit(NOTIFICATION_NEG_LIMIT), - NegentropyOptions::default(), - ) + drop(contact_list); + + let sync = Filter::new() + .pubkey(public_key) + .kinds(vec![ + Kind::TextNote, + Kind::Repost, + Kind::Reaction, + Kind::ZapReceipt, + ]) + .limit(NOTIFICATION_NEG_LIMIT); + + // Sync notification with negentropy + if client + .reconcile(sync, NegentropyOptions::default()) .await + .is_ok() { - Ok(_) => { - if handle.emit_to(EventTarget::Any, "synced", true).is_err() { - println!("Emit event failed.") - } - } - Err(_) => println!("Sync notification failed."), - }; + handle.emit("notification_synchronized", ()).unwrap(); + } - let subscription_id = SubscriptionId::new("notification"); - let subscription = Filter::new() + let notification = Filter::new() .pubkey(public_key) .kinds(vec![ Kind::TextNote, @@ -310,146 +326,12 @@ pub async fn login( .since(Timestamp::now()); // Subscribing for new notification... - let _ = client - .subscribe_with_id(subscription_id, vec![subscription], None) - .await; - - // Handle notifications - client - .handle_notifications(|notification| async { - if let RelayPoolNotification::Message { message, .. } = notification { - if let RelayMessage::Event { - subscription_id, - event, - } = message - { - let id = subscription_id.to_string(); - - if id.starts_with("notification") { - if app - .emit_to( - EventTarget::window("panel"), - "notification", - event.as_json(), - ) - .is_err() - { - println!("Emit new notification failed.") - } - - let handle = app.app_handle(); - let author = client.metadata(event.pubkey).await.unwrap(); - - match event.kind() { - Kind::TextNote => { - if let Err(e) = handle - .notification() - .builder() - .body("Mentioned you in a thread.") - .title( - author - .display_name - .unwrap_or_else(|| "Lume".to_string()), - ) - .show() - { - println!("Failed to show notification: {:?}", e); - } - } - Kind::Repost => { - if let Err(e) = handle - .notification() - .builder() - .body("Reposted your note.") - .title( - author - .display_name - .unwrap_or_else(|| "Lume".to_string()), - ) - .show() - { - println!("Failed to show notification: {:?}", e); - } - } - Kind::Reaction => { - let content = event.content(); - if let Err(e) = handle - .notification() - .builder() - .body(content) - .title( - author - .display_name - .unwrap_or_else(|| "Lume".to_string()), - ) - .show() - { - println!("Failed to show notification: {:?}", e); - } - } - Kind::ZapReceipt => { - if let Err(e) = handle - .notification() - .builder() - .body("Zapped you.") - .title( - author - .display_name - .unwrap_or_else(|| "Lume".to_string()), - ) - .show() - { - println!("Failed to show notification: {:?}", e); - } - } - _ => {} - } - } else if id.starts_with("event-") { - let raw = event.as_json(); - let parsed = if event.kind == Kind::TextNote { - Some(parse_event(&event.content).await) - } else { - None - }; - - if app - .emit_to( - EventTarget::window(id), - "new_reply", - RichEvent { raw, parsed }, - ) - .is_err() - { - println!("Emit new notification failed.") - } - } else if id.starts_with("column-") { - let raw = event.as_json(); - let parsed = if event.kind == Kind::TextNote { - Some(parse_event(&event.content).await) - } else { - None - }; - - if app - .emit_to( - EventTarget::window(id), - "new_event", - RichEvent { raw, parsed }, - ) - .is_err() - { - println!("Emit new notification failed.") - } - } else { - println!("new event: {}", event.as_json()) - } - } else { - println!("new message: {}", message.as_json()) - } - } - Ok(false) - }) + if let Err(e) = client + .subscribe_with_id(notification_id, vec![notification], None) .await + { + println!("Error: {}", e) + } }); Ok(public_key) diff --git a/src-tauri/src/commands/event.rs b/src-tauri/src/commands/event.rs index 1a2f75e1..826fb82a 100644 --- a/src-tauri/src/commands/event.rs +++ b/src-tauri/src/commands/event.rs @@ -5,7 +5,7 @@ use specta::Type; use std::{str::FromStr, time::Duration}; use tauri::State; -use crate::common::{create_event_tags, dedup_event, parse_event, Meta}; +use crate::common::{create_event_tags, filter_converstation, parse_event, Meta}; use crate::{Nostr, FETCH_LIMIT}; #[derive(Debug, Clone, Serialize, Type)] @@ -16,31 +16,21 @@ pub struct RichEvent { #[tauri::command] #[specta::specta] -pub async fn get_event_meta(content: &str) -> Result { - let meta = parse_event(content).await; +pub async fn get_event_meta(content: String) -> Result { + let meta = parse_event(&content).await; Ok(meta) } #[tauri::command] #[specta::specta] -pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result { +pub async fn get_event(id: String, state: State<'_, Nostr>) -> Result { let client = &state.client; - - let event_id = match Nip19::from_bech32(id) { - Ok(val) => match val { - Nip19::EventId(id) => id, - Nip19::Event(event) => event.event_id, - _ => return Err("Event ID is not valid.".into()), - }, - Err(_) => match EventId::from_hex(id) { - Ok(id) => id, - Err(_) => return Err("Event ID is not valid.".into()), - }, - }; + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; + let filter = Filter::new().id(event_id); match client .get_events_of( - vec![Filter::new().id(event_id)], + vec![filter], EventSource::both(Some(Duration::from_secs(5))), ) .await @@ -66,30 +56,49 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result, ) -> Result { let client = &state.client; - let settings = state - .settings - .lock() - .map_err(|err| err.to_string())? - .clone(); - - let event_id = match Nip19::from_bech32(id) { - Ok(val) => match val { - Nip19::EventId(id) => id, - Nip19::Event(event) => event.event_id, - _ => return Err("Event ID is not valid.".into()), - }, - Err(_) => match EventId::from_hex(id) { - Ok(id) => id, - Err(_) => return Err("Event ID is not valid.".into()), - }, - }; + let settings = state.settings.lock().await; + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; + let filter = Filter::new().id(event_id); if !settings.use_relay_hint { + match client + .get_events_of( + vec![filter], + EventSource::both(Some(Duration::from_secs(5))), + ) + .await + { + Ok(events) => { + if let Some(event) = events.first() { + let raw = event.as_json(); + let parsed = if event.kind == Kind::TextNote { + Some(parse_event(&event.content).await) + } else { + None + }; + + Ok(RichEvent { raw, parsed }) + } else { + Err("Cannot found this event with current relay list".into()) + } + } + Err(err) => Err(err.to_string()), + } + } else { + // Add relay hint to relay pool + if let Err(e) = client.add_relay(&relay_hint).await { + return Err(e.to_string()); + } + + if let Err(e) = client.connect_relay(&relay_hint).await { + return Err(e.to_string()); + } + match client .get_events_of( vec![Filter::new().id(event_id)], @@ -113,49 +122,14 @@ pub async fn get_event_from( } Err(err) => Err(err.to_string()), } - } else { - // Add relay hint to relay pool - if let Err(err) = client.add_relay(relay_hint).await { - return Err(err.to_string()); - } - - if client.connect_relay(relay_hint).await.is_ok() { - match client - .get_events_from(vec![relay_hint], vec![Filter::new().id(event_id)], None) - .await - { - Ok(events) => { - if let Some(event) = events.first() { - let raw = event.as_json(); - let parsed = if event.kind == Kind::TextNote { - Some(parse_event(&event.content).await) - } else { - None - }; - - Ok(RichEvent { raw, parsed }) - } else { - Err("Cannot found this event with current relay list".into()) - } - } - Err(err) => Err(err.to_string()), - } - } else { - Err("Relay connection failed.".into()) - } } } #[tauri::command] #[specta::specta] -pub async fn get_replies(id: &str, state: State<'_, Nostr>) -> Result, String> { +pub async fn get_replies(id: String, state: State<'_, Nostr>) -> Result, String> { let client = &state.client; - - let event_id = match EventId::from_hex(id) { - Ok(id) => id, - Err(err) => return Err(err.to_string()), - }; - + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; let filter = Filter::new().kinds(vec![Kind::TextNote]).event(event_id); match client @@ -166,7 +140,7 @@ pub async fn get_replies(id: &str, state: State<'_, Nostr>) -> Result { - let futures = events.into_iter().map(|ev| async move { + let futures = events.iter().map(|ev| async move { let raw = ev.as_json(); let parsed = if ev.kind == Kind::TextNote { Some(parse_event(&ev.content).await) @@ -186,73 +160,63 @@ pub async fn get_replies(id: &str, state: State<'_, Nostr>) -> Result) -> Result<(), String> { +pub async fn subscribe_to(id: String, state: State<'_, Nostr>) -> Result<(), String> { let client = &state.client; - let mut label = "event-".to_owned(); - label.push_str(id); + let subscription_id = SubscriptionId::new(&id); + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; - let sub_id = SubscriptionId::new(label); - let event_id = match EventId::from_hex(id) { - Ok(id) => id, - Err(err) => return Err(err.to_string()), - }; let filter = Filter::new() .kinds(vec![Kind::TextNote]) .event(event_id) .since(Timestamp::now()); - // Subscribe - let _ = client.subscribe_with_id(sub_id, vec![filter], None).await; - - Ok(()) + match client + .subscribe_with_id(subscription_id, vec![filter], None) + .await + { + Ok(_) => Ok(()), + Err(e) => Err(e.to_string()), + } } #[tauri::command] #[specta::specta] pub async fn get_events_by( - public_key: &str, - as_of: Option<&str>, + public_key: String, + limit: i32, state: State<'_, Nostr>, ) -> Result, String> { let client = &state.client; + let author = PublicKey::parse(&public_key).map_err(|err| err.to_string())?; - match PublicKey::from_str(public_key) { - Ok(author) => { - let until = match as_of { - Some(until) => Timestamp::from_str(until).map_err(|err| err.to_string())?, - None => Timestamp::now(), - }; - let filter = Filter::new() - .kinds(vec![Kind::TextNote, Kind::Repost]) - .author(author) - .limit(FETCH_LIMIT) - .until(until); + let filter = Filter::new() + .kinds(vec![Kind::TextNote]) + .author(author) + .limit(limit as usize); - match client - .get_events_of( - vec![filter], - EventSource::both(Some(Duration::from_secs(5))), - ) - .await - { - Ok(events) => { - let futures = events.into_iter().map(|ev| async move { - let raw = ev.as_json(); - let parsed = if ev.kind == Kind::TextNote { - Some(parse_event(&ev.content).await) - } else { - None - }; + match client + .get_events_of( + vec![filter], + EventSource::both(Some(Duration::from_secs(5))), + ) + .await + { + Ok(events) => { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { + let raw = ev.as_json(); + let parsed = if ev.kind == Kind::TextNote { + Some(parse_event(&ev.content).await) + } else { + None + }; - RichEvent { raw, parsed } - }); - let rich_events = join_all(futures).await; + RichEvent { raw, parsed } + }); + let rich_events = join_all(futures).await; - Ok(rich_events) - } - Err(err) => Err(err.to_string()), - } + Ok(rich_events) } Err(err) => Err(err.to_string()), } @@ -260,34 +224,33 @@ pub async fn get_events_by( #[tauri::command] #[specta::specta] -pub async fn get_local_events( +pub async fn get_events_from_contacts( until: Option<&str>, state: State<'_, Nostr>, ) -> Result, String> { let client = &state.client; - let contact_list = state - .contact_list - .lock() - .map_err(|err| err.to_string())? - .clone(); + let contact_list = state.contact_list.lock().await; + let authors: Vec = contact_list.iter().map(|f| f.public_key).collect(); + + if authors.is_empty() { + return Err("Contact List is empty.".into()); + } let as_of = match until { Some(until) => Timestamp::from_str(until).map_err(|err| err.to_string())?, None => Timestamp::now(), }; - let authors: Vec = contact_list.into_iter().map(|f| f.public_key).collect(); - let filter = Filter::new() .kinds(vec![Kind::TextNote, Kind::Repost]) - .limit(64) + .limit(FETCH_LIMIT) .until(as_of) .authors(authors); match client.database().query(vec![filter], Order::Desc).await { Ok(events) => { - let dedup = dedup_event(&events); - let futures = dedup.into_iter().map(|ev| async move { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { let raw = ev.as_json(); let parsed = if ev.kind == Kind::TextNote { Some(parse_event(&ev.content).await) @@ -305,31 +268,6 @@ pub async fn get_local_events( } } -#[tauri::command] -#[specta::specta] -pub async fn listen_local_event(label: &str, state: State<'_, Nostr>) -> Result<(), String> { - let client = &state.client; - - let contact_list = state - .contact_list - .lock() - .map_err(|err| err.to_string())? - .clone(); - - let authors: Vec = contact_list.into_iter().map(|f| f.public_key).collect(); - let sub_id = SubscriptionId::new(label); - - let filter = Filter::new() - .kinds(vec![Kind::TextNote, Kind::Repost]) - .authors(authors) - .since(Timestamp::now()); - - // Subscribe - let _ = client.subscribe_with_id(sub_id, vec![filter], None).await; - - Ok(()) -} - #[tauri::command] #[specta::specta] pub async fn get_group_events( @@ -345,7 +283,7 @@ pub async fn get_group_events( }; let authors: Vec = public_keys - .into_iter() + .iter() .map(|p| { if p.starts_with("npub1") { PublicKey::from_bech32(p).map_err(|err| err.to_string()) @@ -369,9 +307,8 @@ pub async fn get_group_events( .await { Ok(events) => { - let dedup = dedup_event(&events); - - let futures = dedup.into_iter().map(|ev| async move { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { let raw = ev.as_json(); let parsed = if ev.kind == Kind::TextNote { Some(parse_event(&ev.content).await) @@ -415,8 +352,8 @@ pub async fn get_global_events( .await { Ok(events) => { - let dedup = dedup_event(&events); - let futures = dedup.into_iter().map(|ev| async move { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { let raw = ev.as_json(); let parsed = if ev.kind == Kind::TextNote { Some(parse_event(&ev.content).await) @@ -460,8 +397,8 @@ pub async fn get_hashtag_events( .await { Ok(events) => { - let dedup = dedup_event(&events); - let futures = dedup.into_iter().map(|ev| async move { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { let raw = ev.as_json(); let parsed = if ev.kind == Kind::TextNote { Some(parse_event(&ev.content).await) @@ -540,17 +477,14 @@ pub async fn reply( // Create tags from content let mut tags = create_event_tags(&content); - let reply_id = match EventId::from_hex(to) { - Ok(val) => val, - Err(_) => return Err("Event is not valid.".into()), - }; + let reply_id = EventId::parse(&to).map_err(|err| err.to_string())?; match database .query(vec![Filter::new().id(reply_id)], Order::Desc) .await { Ok(events) => { - if let Some(event) = events.into_iter().next() { + if let Some(event) = events.first() { let relay_hint = if let Some(relays) = database .event_seen_on_relays(event.id) .await @@ -585,7 +519,7 @@ pub async fn reply( .query(vec![Filter::new().id(root_id)], Order::Desc) .await { - if let Some(event) = events.into_iter().next() { + if let Some(event) = events.first() { let relay_hint = if let Some(relays) = database .event_seen_on_relays(event.id) .await @@ -627,13 +561,21 @@ pub async fn repost(raw: &str, state: State<'_, Nostr>) -> Result) -> Result { +pub async fn delete(id: String, state: State<'_, Nostr>) -> Result { let client = &state.client; + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; - let event_id = match EventId::from_hex(id) { - Ok(id) => id, - Err(_) => return Err("ID is not valid.".into()), - }; + match client.delete_event(event_id).await { + Ok(event_id) => Ok(event_id.to_string()), + Err(err) => Err(err.to_string()), + } +} + +#[tauri::command] +#[specta::specta] +pub async fn event_to_bech32(id: String, state: State<'_, Nostr>) -> Result { + let client = &state.client; + let event_id = EventId::parse(&id).map_err(|err| err.to_string())?; let seens = client .database() @@ -662,11 +604,7 @@ pub async fn event_to_bech32(id: &str, state: State<'_, Nostr>) -> Result) -> Result { let client = &state.client; - - let public_key = match PublicKey::from_str(user) { - Ok(pk) => pk, - Err(_) => return Err("Public Key is not valid.".into()), - }; + let public_key = PublicKey::parse(user).map_err(|err| err.to_string())?; match client .get_events_of( @@ -704,12 +642,48 @@ pub async fn user_to_bech32(user: &str, state: State<'_, Nostr>) -> Result) -> Result<(), ()> { +pub async fn search( + query: String, + until: Option, + state: State<'_, Nostr>, +) -> Result, String> { let client = &state.client; - let sub_id = SubscriptionId::new(id); - // Remove subscription - client.unsubscribe(sub_id).await; + let timestamp = match until { + Some(str) => Timestamp::from_str(&str).map_err(|err| err.to_string())?, + None => Timestamp::now(), + }; - Ok(()) + let filter = Filter::new() + .kinds(vec![Kind::TextNote, Kind::Metadata]) + .search(query) + .until(timestamp) + .limit(FETCH_LIMIT); + + match client + .get_events_of( + vec![filter], + EventSource::both(Some(Duration::from_secs(5))), + ) + .await + { + Ok(events) => { + let fils = filter_converstation(events); + let futures = fils.iter().map(|ev| async move { + let raw = ev.as_json(); + let parsed = if ev.kind == Kind::TextNote { + Some(parse_event(&ev.content).await) + } else { + None + }; + + RichEvent { raw, parsed } + }); + + let rich_events = join_all(futures).await; + + Ok(rich_events) + } + Err(e) => Err(e.to_string()), + } } diff --git a/src-tauri/src/commands/metadata.rs b/src-tauri/src/commands/metadata.rs index 3c0f0e83..1aa138e5 100644 --- a/src-tauri/src/commands/metadata.rs +++ b/src-tauri/src/commands/metadata.rs @@ -1,19 +1,31 @@ use keyring::Entry; use nostr_sdk::prelude::*; +use serde::{Deserialize, Serialize}; +use specta::Type; use std::{str::FromStr, time::Duration}; use tauri::State; +use tauri_specta::Event; -use crate::{Nostr, Settings}; +use crate::{NewSettings, Nostr, Settings}; + +#[derive(Clone, Serialize, Deserialize, Type)] +pub struct Profile { + name: String, + display_name: String, + about: Option, + picture: String, + banner: Option, + nip05: Option, + lud16: Option, + website: Option, +} #[tauri::command] #[specta::specta] pub async fn get_profile(id: Option, state: State<'_, Nostr>) -> Result { let client = &state.client; let public_key: PublicKey = match id { - Some(user_id) => match PublicKey::from_str(&user_id) { - Ok(val) => val, - Err(_) => return Err("Public Key is not valid".into()), - }, + Some(user_id) => PublicKey::parse(&user_id).map_err(|e| e.to_string())?, None => client.signer().await.unwrap().public_key().await.unwrap(), }; @@ -22,43 +34,46 @@ pub async fn get_profile(id: Option, state: State<'_, Nostr>) -> Result< .kind(Kind::Metadata) .limit(1); - let query = client + match client .get_events_of( vec![filter], EventSource::both(Some(Duration::from_secs(3))), ) - .await; - - if let Ok(events) = query { - if let Some(event) = events.first() { - if let Ok(metadata) = Metadata::from_json(&event.content) { - Ok(metadata.as_json()) + .await + { + Ok(events) => { + if let Some(event) = events.first() { + if let Ok(metadata) = Metadata::from_json(&event.content) { + Ok(metadata.as_json()) + } else { + Err("Parse metadata failed".into()) + } } else { - Err("Parse metadata failed".into()) + Ok(Metadata::new().as_json()) } - } else { - Ok(Metadata::new().as_json()) } - } else { - Err("Get metadata failed".into()) + Err(e) => Err(e.to_string()), } } #[tauri::command] #[specta::specta] pub async fn set_contact_list( - public_keys: Vec<&str>, + public_keys: Vec, state: State<'_, Nostr>, ) -> Result { let client = &state.client; let contact_list: Vec = public_keys .into_iter() - .filter_map(|p| match PublicKey::from_hex(p) { + .filter_map(|p| match PublicKey::parse(p) { Ok(pk) => Some(Contact::new(pk, None, Some(""))), Err(_) => None, }) .collect(); + // Update local state + state.contact_list.lock().await.clone_from(&contact_list); + match client.set_contact_list(contact_list).await { Ok(_) => Ok(true), Err(err) => Err(err.to_string()), @@ -89,77 +104,69 @@ pub async fn get_contact_list(state: State<'_, Nostr>) -> Result, St #[tauri::command] #[specta::specta] -pub async fn create_profile( - name: &str, - display_name: &str, - about: &str, - picture: &str, - banner: &str, - nip05: &str, - lud16: &str, - website: &str, - state: State<'_, Nostr>, -) -> Result { +pub async fn set_profile(profile: Profile, state: State<'_, Nostr>) -> Result { let client = &state.client; let mut metadata = Metadata::new() - .name(name) - .display_name(display_name) - .about(about) - .nip05(nip05) - .lud16(lud16); + .name(profile.name) + .display_name(profile.display_name) + .about(profile.about.unwrap_or_default()) + .nip05(profile.nip05.unwrap_or_default()) + .lud16(profile.lud16.unwrap_or_default()); - if let Ok(url) = Url::parse(picture) { + if let Ok(url) = Url::parse(&profile.picture) { metadata = metadata.picture(url) } - if let Ok(url) = Url::parse(banner) { - metadata = metadata.banner(url) + if let Some(b) = profile.banner { + if let Ok(url) = Url::parse(&b) { + metadata = metadata.banner(url) + } } - if let Ok(url) = Url::parse(website) { - metadata = metadata.website(url) + if let Some(w) = profile.website { + if let Ok(url) = Url::parse(&w) { + metadata = metadata.website(url) + } } - if let Ok(event_id) = client.set_metadata(&metadata).await { - Ok(event_id.to_string()) - } else { - Err("Create profile failed".into()) + match client.set_metadata(&metadata).await { + Ok(id) => Ok(id.to_string()), + Err(e) => Err(e.to_string()), } } #[tauri::command] #[specta::specta] pub async fn is_contact_list_empty(state: State<'_, Nostr>) -> Result { - let contact_list = state.contact_list.lock().unwrap(); - Ok(contact_list.is_empty()) + Ok(state.contact_list.lock().await.is_empty()) } #[tauri::command] #[specta::specta] pub async fn check_contact(hex: String, state: State<'_, Nostr>) -> Result { - let contact_list = state.contact_list.lock().unwrap(); + let contact_list = state.contact_list.lock().await; - match PublicKey::from_str(&hex) { + match PublicKey::parse(&hex) { Ok(public_key) => match contact_list.iter().position(|x| x.public_key == public_key) { Some(_) => Ok(true), None => Ok(false), }, - Err(err) => Err(err.to_string()), + Err(e) => Err(e.to_string()), } } #[tauri::command] #[specta::specta] pub async fn toggle_contact( - hex: &str, - alias: Option<&str>, + id: String, + alias: Option, state: State<'_, Nostr>, ) -> Result { let client = &state.client; - match client.get_contact_list(None).await { + match client.get_contact_list(Some(Duration::from_secs(5))).await { Ok(mut contact_list) => { - let public_key = PublicKey::from_str(hex).unwrap(); + let public_key = PublicKey::parse(&id).map_err(|e| e.to_string())?; match contact_list.iter().position(|x| x.public_key == public_key) { Some(index) => { @@ -175,7 +182,7 @@ pub async fn toggle_contact( } // Update local state - state.contact_list.lock().unwrap().clone_from(&contact_list); + state.contact_list.lock().await.clone_from(&contact_list); // Publish match client.set_contact_list(contact_list).await { @@ -189,9 +196,9 @@ pub async fn toggle_contact( #[tauri::command] #[specta::specta] -pub async fn set_nstore( - key: &str, - content: &str, +pub async fn set_lume_store( + key: String, + content: String, state: State<'_, Nostr>, ) -> Result { let client = &state.client; @@ -202,7 +209,6 @@ pub async fn set_nstore( .nip44_encrypt(public_key, content) .await .map_err(|e| e.to_string())?; - let tag = Tag::identifier(key); let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]); @@ -214,7 +220,7 @@ pub async fn set_nstore( #[tauri::command] #[specta::specta] -pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result { +pub async fn get_lume_store(key: String, state: State<'_, Nostr>) -> Result { let client = &state.client; let signer = client.signer().await.map_err(|e| e.to_string())?; let public_key = signer.public_key().await.map_err(|e| e.to_string())?; @@ -226,16 +232,12 @@ pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result { if let Some(event) = events.first() { - let content = event.content(); - match signer.nip44_decrypt(public_key, content).await { + match signer.nip44_decrypt(public_key, event.content()).await { Ok(decrypted) => Ok(decrypted), Err(_) => Err(event.content.to_string()), } @@ -316,7 +318,7 @@ pub async fn zap_profile( state: State<'_, Nostr>, ) -> Result { let client = &state.client; - let public_key: PublicKey = PublicKey::from_str(id).map_err(|e| e.to_string())?; + let public_key: PublicKey = PublicKey::parse(id).map_err(|e| e.to_string())?; let details = ZapDetails::new(ZapType::Private).message(message); let num = amount.parse::().map_err(|e| e.to_string())?; @@ -361,7 +363,7 @@ pub async fn zap_event( #[tauri::command] #[specta::specta] -pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result { +pub async fn copy_friend(npub: &str, state: State<'_, Nostr>) -> Result { let client = &state.client; match PublicKey::from_bech32(npub) { @@ -408,7 +410,7 @@ pub async fn get_following( public_key: &str, ) -> Result, String> { let client = &state.client; - let public_key = PublicKey::from_str(public_key).map_err(|e| e.to_string())?; + let public_key = PublicKey::parse(public_key).map_err(|e| e.to_string())?; let filter = Filter::new().kind(Kind::ContactList).author(public_key); let events = match client @@ -444,7 +446,7 @@ pub async fn get_followers( public_key: &str, ) -> Result, String> { let client = &state.client; - let public_key = PublicKey::from_str(public_key).map_err(|e| e.to_string())?; + let public_key = PublicKey::parse(public_key).map_err(|e| e.to_string())?; let filter = Filter::new().kind(Kind::ContactList).custom_tag( SingleLetterTag::lowercase(Alphabet::P), @@ -505,28 +507,51 @@ pub async fn get_notifications(state: State<'_, Nostr>) -> Result, S #[tauri::command] #[specta::specta] pub async fn get_settings(state: State<'_, Nostr>) -> Result { - let settings = state.settings.lock().unwrap().clone(); - Ok(settings) + Ok(state.settings.lock().await.clone()) } #[tauri::command] #[specta::specta] -pub async fn set_new_settings(settings: &str, state: State<'_, Nostr>) -> Result<(), ()> { - let parsed: Settings = - serde_json::from_str(settings).expect("Could not parse settings payload"); - *state.settings.lock().unwrap() = parsed; +pub async fn set_settings( + settings: &str, + state: State<'_, Nostr>, + handle: tauri::AppHandle, +) -> Result<(), String> { + let client = &state.client; + let ident = "lume_v4:settings"; + let signer = client.signer().await.map_err(|e| e.to_string())?; + let public_key = signer.public_key().await.map_err(|e| e.to_string())?; + let encrypted = signer + .nip44_encrypt(public_key, settings) + .await + .map_err(|e| e.to_string())?; + let tag = Tag::identifier(ident); + let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]); - Ok(()) -} + match client.send_event_builder(builder).await { + Ok(_) => { + let parsed: Settings = serde_json::from_str(settings).map_err(|e| e.to_string())?; -#[tauri::command] -#[specta::specta] -pub async fn verify_nip05(key: &str, nip05: &str) -> Result { - match PublicKey::from_str(key) { - Ok(public_key) => { - let status = nip05::verify(&public_key, nip05, None).await; - Ok(status.is_ok()) + // Update state + state.settings.lock().await.clone_from(&parsed); + + // Emit new changes to frontend + NewSettings(parsed).emit(&handle).unwrap(); + + Ok(()) } Err(err) => Err(err.to_string()), } } + +#[tauri::command] +#[specta::specta] +pub async fn verify_nip05(id: String, nip05: &str) -> Result { + match PublicKey::from_str(&id) { + Ok(public_key) => match nip05::verify(&public_key, nip05, None).await { + Ok(status) => Ok(status), + Err(e) => Err(e.to_string()), + }, + Err(e) => Err(e.to_string()), + } +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index bacd0a99..b768bfcc 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -2,6 +2,4 @@ pub mod account; pub mod event; pub mod metadata; pub mod relay; -#[cfg(target_os = "macos")] -pub mod tray; pub mod window; diff --git a/src-tauri/src/commands/tray.rs b/src-tauri/src/commands/tray.rs deleted file mode 100644 index 2dd94b37..00000000 --- a/src-tauri/src/commands/tray.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::path::PathBuf; -use tauri::window::{Effect, EffectsBuilder}; -use tauri::{ - tray::{MouseButtonState, TrayIconEvent}, - WebviewWindowBuilder, -}; -use tauri::{AppHandle, Manager, WebviewUrl}; -use tauri_nspanel::ManagerExt; - -use crate::macos::{ - position_menubar_panel, set_corner_radius, setup_menubar_panel_listeners, - swizzle_to_menubar_panel, -}; - -pub fn create_tray_panel(account: &str, app: &AppHandle) { - let tray = app.tray_by_id("main").unwrap(); - - tray.on_tray_icon_event(|tray, event| { - if let TrayIconEvent::Click { button_state, .. } = event { - if button_state == MouseButtonState::Up { - let app = tray.app_handle(); - let panel = app.get_webview_panel("panel").unwrap(); - - match panel.is_visible() { - true => panel.order_out(None), - false => { - position_menubar_panel(app, 0.0); - panel.show(); - } - } - } - } - }); - - if let Some(window) = app.get_webview_window("panel") { - let _ = window.destroy(); - }; - - let url = format!("/{}/panel", account); - - let window = WebviewWindowBuilder::new(app, "panel", WebviewUrl::App(PathBuf::from(url))) - .title("Panel") - .inner_size(350.0, 500.0) - .fullscreen(false) - .resizable(false) - .visible(false) - .decorations(false) - .transparent(true) - .build() - .unwrap(); - - let _ = window.set_effects( - EffectsBuilder::new() - .effect(Effect::Popover) - .state(tauri::window::EffectState::FollowsWindowActiveState) - .build(), - ); - - set_corner_radius(&window, 13.0); - - // Convert window to panel - swizzle_to_menubar_panel(app); - setup_menubar_panel_listeners(app); -} diff --git a/src-tauri/src/commands/window.rs b/src-tauri/src/commands/window.rs index 7f09eb7e..4994aa92 100644 --- a/src-tauri/src/commands/window.rs +++ b/src-tauri/src/commands/window.rs @@ -8,9 +8,8 @@ use tauri::utils::config::WindowEffectsConfig; use tauri::window::Effect; #[cfg(target_os = "macos")] use tauri::TitleBarStyle; -use tauri::WebviewWindowBuilder; use tauri::{LogicalPosition, LogicalSize, Manager, WebviewUrl}; -#[cfg(target_os = "windows")] +use tauri::{WebviewBuilder, WebviewWindowBuilder}; use tauri_plugin_decorum::WebviewWindowExt; #[derive(Serialize, Deserialize, Type)] @@ -45,7 +44,7 @@ pub fn create_column(column: Column, app_handle: tauri::AppHandle) -> Result Result Result { match app_handle.get_webview(&label) { - Some(webview) => { - if webview.close().is_ok() { - Ok(true) - } else { - Ok(false) - } - } - None => Err("Column not found.".into()), + Some(webview) => Ok(webview.close().is_ok()), + None => Err("Not found.".into()), } } @@ -86,16 +79,10 @@ pub fn reposition_column( x: f32, y: f32, app_handle: tauri::AppHandle, -) -> Result<(), String> { +) -> Result { match app_handle.get_webview(&label) { - Some(webview) => { - if webview.set_position(LogicalPosition::new(x, y)).is_ok() { - Ok(()) - } else { - Err("Reposition column failed".into()) - } - } - None => Err("Webview not found".into()), + Some(webview) => Ok(webview.set_position(LogicalPosition::new(x, y)).is_ok()), + None => Err("Not found".into()), } } @@ -106,36 +93,25 @@ pub fn resize_column( width: f32, height: f32, app_handle: tauri::AppHandle, -) -> Result<(), String> { +) -> Result { match app_handle.get_webview(&label) { - Some(webview) => { - if webview.set_size(LogicalSize::new(width, height)).is_ok() { - Ok(()) - } else { - Err("Resize column failed".into()) - } - } - None => Err("Webview not found".into()), + Some(webview) => Ok(webview.set_size(LogicalSize::new(width, height)).is_ok()), + None => Err("Not found".into()), } } #[tauri::command(async)] #[specta::specta] -pub fn reload_column(label: String, app_handle: tauri::AppHandle) -> Result<(), String> { +pub fn reload_column(label: String, app_handle: tauri::AppHandle) -> Result { match app_handle.get_webview(&label) { - Some(webview) => { - if webview.eval("window.location.reload()").is_ok() { - Ok(()) - } else { - Err("Reload column failed".into()) - } - } - None => Err("Webview not found".into()), + Some(webview) => Ok(webview.eval("window.location.reload()").is_ok()), + None => Err("Not found".into()), } } #[tauri::command] #[specta::specta] +#[cfg(target_os = "macos")] pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), String> { if let Some(window) = app_handle.get_window(&window.label) { if window.is_visible().unwrap_or_default() { @@ -145,7 +121,6 @@ pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), S let _ = window.set_focus(); }; } else { - #[cfg(target_os = "macos")] let window = WebviewWindowBuilder::new( &app_handle, &window.label, @@ -168,7 +143,25 @@ pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), S .build() .unwrap(); - #[cfg(target_os = "windows")] + // Restore native border + window.add_border(None); + } + + Ok(()) +} + +#[tauri::command(async)] +#[specta::specta] +#[cfg(target_os = "windows")] +pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), String> { + if let Some(window) = app_handle.get_window(&window.label) { + if window.is_visible().unwrap_or_default() { + let _ = window.set_focus(); + } else { + let _ = window.show(); + let _ = window.set_focus(); + }; + } else { let window = WebviewWindowBuilder::new( &app_handle, &window.label, @@ -180,6 +173,7 @@ pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), S .minimizable(window.minimizable) .maximizable(window.maximizable) .transparent(true) + .decorations(false) .effects(WindowEffectsConfig { state: None, effects: vec![Effect::Mica], @@ -190,12 +184,7 @@ pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), S .unwrap(); // Set decoration - #[cfg(target_os = "windows")] window.create_overlay_titlebar().unwrap(); - - // Restore native border - #[cfg(target_os = "macos")] - window.add_border(None); } Ok(()) @@ -203,7 +192,7 @@ pub fn open_window(window: Window, app_handle: tauri::AppHandle) -> Result<(), S #[tauri::command] #[specta::specta] -pub fn open_main_window(app: tauri::AppHandle) { +pub fn reopen_lume(app: tauri::AppHandle) { if let Some(window) = app.get_window("main") { if window.is_visible().unwrap_or_default() { let _ = window.set_focus(); @@ -225,11 +214,25 @@ pub fn open_main_window(app: tauri::AppHandle) { // Restore native border #[cfg(target_os = "macos")] window.add_border(None); + + // Set a custom inset to the traffic lights + #[cfg(target_os = "macos")] + window.set_traffic_lights_inset(7.0, 13.0).unwrap(); + + #[cfg(target_os = "macos")] + let win = window.clone(); + + #[cfg(target_os = "macos")] + window.on_window_event(move |event| { + if let tauri::WindowEvent::ThemeChanged(_) = event { + win.set_traffic_lights_inset(7.0, 13.0).unwrap(); + } + }); } } #[tauri::command] #[specta::specta] -pub fn force_quit() { +pub fn quit() { std::process::exit(0) } diff --git a/src-tauri/src/common.rs b/src-tauri/src/common.rs index 3201dea0..f69717d5 100644 --- a/src-tauri/src/common.rs +++ b/src-tauri/src/common.rs @@ -46,106 +46,27 @@ const NOSTR_MENTIONS: [&str; 10] = [ const IMAGES: [&str; 7] = ["jpg", "jpeg", "gif", "png", "webp", "avif", "tiff"]; const VIDEOS: [&str; 5] = ["mp4", "mov", "avi", "webm", "mkv"]; -pub async fn init_nip65(client: &Client) { - let signer = match client.signer().await { - Ok(signer) => signer, - Err(e) => { - eprintln!("Failed to get signer: {:?}", e); - return; - } - }; - let public_key = match signer.public_key().await { - Ok(public_key) => public_key, - Err(e) => { - eprintln!("Failed to get public key: {:?}", e); - return; - } - }; - - let filter = Filter::new() - .author(public_key) - .kind(Kind::RelayList) - .limit(1); - - if let Ok(events) = client - .get_events_of( - vec![filter], - EventSource::both(Some(Duration::from_secs(5))), - ) - .await - { - if let Some(event) = events.first() { - let relay_list = nip65::extract_relay_list(event); - for (url, metadata) in relay_list { - let opts = match metadata { - Some(RelayMetadata::Read) => RelayOptions::new().read(true).write(false), - Some(_) => RelayOptions::new().write(true).read(false), - None => RelayOptions::default(), - }; - if let Err(e) = client.add_relay_with_opts(&url.to_string(), opts).await { - eprintln!("Failed to add relay {}: {:?}", url, e); - } - if let Err(e) = client.connect_relay(url.to_string()).await { - eprintln!("Failed to connect to relay {}: {:?}", url, e); - } else { - println!("Connecting to relay: {} - {:?}", url, metadata); - } - } - } - } else { - eprintln!("Failed to get events for RelayList."); - } -} - -pub async fn get_user_settings(client: &Client) -> Result { - let ident = "lume:settings"; - let signer = client - .signer() - .await - .map_err(|e| format!("Failed to get signer: {:?}", e))?; - let public_key = signer - .public_key() - .await - .map_err(|e| format!("Failed to get public key: {:?}", e))?; - - let filter = Filter::new() - .author(public_key) - .kind(Kind::ApplicationSpecificData) - .identifier(ident) - .limit(1); - - match client - .get_events_of( - vec![filter], - EventSource::both(Some(Duration::from_secs(5))), - ) - .await - { - Ok(events) => { - if let Some(event) = events.first() { - let content = event.content(); - match signer.nip44_decrypt(public_key, content).await { - Ok(decrypted) => match serde_json::from_str(&decrypted) { - Ok(parsed) => Ok(parsed), - Err(_) => Err("Could not parse settings payload".into()), - }, - Err(e) => Err(format!("Failed to decrypt settings content: {:?}", e)), - } - } else { - Err("Settings not found.".into()) - } - } - Err(e) => Err(format!( - "Failed to get events for ApplicationSpecificData: {:?}", - e - )), - } -} - pub fn get_latest_event(events: &[Event]) -> Option<&Event> { events.iter().next() } +pub fn filter_converstation(events: Vec) -> Vec { + events + .into_iter() + .filter_map(|ev| { + let tags = ev.get_tags_content(TagKind::SingleLetter(SingleLetterTag::lowercase( + Alphabet::E, + ))); + + if tags.is_empty() { + Some(ev) + } else { + None + } + }) + .collect::>() +} + pub fn dedup_event(events: &[Event]) -> Vec { let mut seen_ids = HashSet::new(); events @@ -331,6 +252,102 @@ pub fn create_event_tags(content: &str) -> Vec { tags } +pub async fn init_nip65(client: &Client) { + let signer = match client.signer().await { + Ok(signer) => signer, + Err(e) => { + eprintln!("Failed to get signer: {:?}", e); + return; + } + }; + let public_key = match signer.public_key().await { + Ok(public_key) => public_key, + Err(e) => { + eprintln!("Failed to get public key: {:?}", e); + return; + } + }; + + let filter = Filter::new() + .author(public_key) + .kind(Kind::RelayList) + .limit(1); + + if let Ok(events) = client + .get_events_of( + vec![filter], + EventSource::both(Some(Duration::from_secs(5))), + ) + .await + { + if let Some(event) = events.first() { + let relay_list = nip65::extract_relay_list(event); + for (url, metadata) in relay_list { + let opts = match metadata { + Some(RelayMetadata::Read) => RelayOptions::new().read(true).write(false), + Some(_) => RelayOptions::new().write(true).read(false), + None => RelayOptions::default(), + }; + if let Err(e) = client.add_relay_with_opts(&url.to_string(), opts).await { + eprintln!("Failed to add relay {}: {:?}", url, e); + } + if let Err(e) = client.connect_relay(url.to_string()).await { + eprintln!("Failed to connect to relay {}: {:?}", url, e); + } else { + println!("Connecting to relay: {} - {:?}", url, metadata); + } + } + } + } else { + eprintln!("Failed to get events for RelayList."); + } +} + +pub async fn get_user_settings(client: &Client) -> Result { + let ident = "lume_v4:settings"; + let signer = client + .signer() + .await + .map_err(|e| format!("Failed to get signer: {:?}", e))?; + let public_key = signer + .public_key() + .await + .map_err(|e| format!("Failed to get public key: {:?}", e))?; + + let filter = Filter::new() + .author(public_key) + .kind(Kind::ApplicationSpecificData) + .identifier(ident) + .limit(1); + + match client + .get_events_of( + vec![filter], + EventSource::both(Some(Duration::from_secs(5))), + ) + .await + { + Ok(events) => { + if let Some(event) = events.first() { + let content = event.content(); + match signer.nip44_decrypt(public_key, content).await { + Ok(decrypted) => match serde_json::from_str(&decrypted) { + Ok(parsed) => Ok(parsed), + Err(_) => Err("Could not parse settings payload".into()), + }, + Err(e) => Err(format!("Failed to decrypt settings content: {:?}", e)), + } + } else { + Err("Settings not found.".into()) + } + } + Err(e) => Err(format!( + "Failed to get events for ApplicationSpecificData: {:?}", + e + )), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src-tauri/src/macos.rs b/src-tauri/src/macos.rs deleted file mode 100644 index 3f14f9e4..00000000 --- a/src-tauri/src/macos.rs +++ /dev/null @@ -1,173 +0,0 @@ -use std::ffi::CString; -use tauri::{AppHandle, Emitter, Listener, Manager, WebviewWindow}; -use tauri_nspanel::{ - block::ConcreteBlock, - cocoa::{ - appkit::{NSMainMenuWindowLevel, NSView, NSWindow, NSWindowCollectionBehavior}, - base::{id, nil}, - foundation::{NSPoint, NSRect}, - }, - objc::{class, msg_send, runtime::NO, sel, sel_impl}, - panel_delegate, ManagerExt, WebviewWindowExt, -}; - -#[allow(non_upper_case_globals)] -const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7; - -pub fn swizzle_to_menubar_panel(app_handle: &tauri::AppHandle) { - let panel_delegate = panel_delegate!(SpotlightPanelDelegate { - window_did_resign_key - }); - - let window = app_handle.get_webview_window("panel").unwrap(); - - let panel = window.to_panel().unwrap(); - - let handle = app_handle.clone(); - - panel_delegate.set_listener(Box::new(move |delegate_name: String| { - if delegate_name.as_str() == "window_did_resign_key" { - let _ = handle.emit("menubar_panel_did_resign_key", ()); - } - })); - - panel.set_level(NSMainMenuWindowLevel + 1); - - panel.set_style_mask(NSWindowStyleMaskNonActivatingPanel); - - panel.set_collection_behaviour( - NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces - | NSWindowCollectionBehavior::NSWindowCollectionBehaviorStationary - | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary, - ); - - panel.set_delegate(panel_delegate); -} - -pub fn setup_menubar_panel_listeners(app_handle: &AppHandle) { - fn hide_menubar_panel(app_handle: &tauri::AppHandle) { - if check_menubar_frontmost() { - return; - } - - let panel = app_handle.get_webview_panel("panel").unwrap(); - - panel.order_out(None); - } - - let handle = app_handle.clone(); - - app_handle.listen_any("menubar_panel_did_resign_key", move |_| { - hide_menubar_panel(&handle); - }); - - let handle = app_handle.clone(); - - let callback = Box::new(move || { - hide_menubar_panel(&handle); - }); - - register_workspace_listener( - "NSWorkspaceDidActivateApplicationNotification".into(), - callback.clone(), - ); - - register_workspace_listener( - "NSWorkspaceActiveSpaceDidChangeNotification".into(), - callback, - ); -} - -pub fn set_corner_radius(window: &WebviewWindow, radius: f64) { - let win: id = window.ns_window().unwrap() as _; - - unsafe { - let view: id = win.contentView(); - - view.wantsLayer(); - - let layer: id = view.layer(); - - let _: () = msg_send![layer, setCornerRadius: radius]; - } -} - -pub fn position_menubar_panel(app_handle: &tauri::AppHandle, padding_top: f64) { - let window = app_handle.get_webview_window("panel").unwrap(); - - let monitor = monitor::get_monitor_with_cursor().unwrap(); - - let scale_factor = monitor.scale_factor(); - - let visible_area = monitor.visible_area(); - - let monitor_pos = visible_area.position().to_logical::(scale_factor); - - let monitor_size = visible_area.size().to_logical::(scale_factor); - - let mouse_location: NSPoint = unsafe { msg_send![class!(NSEvent), mouseLocation] }; - - let handle: id = window.ns_window().unwrap() as _; - - let mut win_frame: NSRect = unsafe { msg_send![handle, frame] }; - - win_frame.origin.y = (monitor_pos.y + monitor_size.height) - win_frame.size.height; - - win_frame.origin.y -= padding_top; - - win_frame.origin.x = { - let top_right = mouse_location.x + (win_frame.size.width / 2.0); - - let is_offscreen = top_right > monitor_pos.x + monitor_size.width; - - if !is_offscreen { - mouse_location.x - (win_frame.size.width / 2.0) - } else { - let diff = top_right - (monitor_pos.x + monitor_size.width); - - mouse_location.x - (win_frame.size.width / 2.0) - diff - } - }; - - let _: () = unsafe { msg_send![handle, setFrame: win_frame display: NO] }; -} - -fn register_workspace_listener(name: String, callback: Box) { - let workspace: id = unsafe { msg_send![class!(NSWorkspace), sharedWorkspace] }; - let notification_center: id = unsafe { msg_send![workspace, notificationCenter] }; - - let block = ConcreteBlock::new(move |_notif: id| { - callback(); - }); - - let block = block.copy(); - - let name: id = - unsafe { msg_send![class!(NSString), stringWithCString: CString::new(name).unwrap()] }; - - unsafe { - let _: () = msg_send![ - notification_center, - addObserverForName: name object: nil queue: nil usingBlock: block - ]; - } -} - -fn app_pid() -> i32 { - let process_info: id = unsafe { msg_send![class!(NSProcessInfo), processInfo] }; - let pid: i32 = unsafe { msg_send![process_info, processIdentifier] }; - - pid -} - -fn get_frontmost_app_pid() -> i32 { - let workspace: id = unsafe { msg_send![class!(NSWorkspace), sharedWorkspace] }; - let frontmost_application: id = unsafe { msg_send![workspace, frontmostApplication] }; - let pid: i32 = unsafe { msg_send![frontmost_application, processIdentifier] }; - - pid -} - -pub fn check_menubar_frontmost() -> bool { - get_frontmost_app_pid() == app_pid() -} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index cb2658ff..ab12f28c 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,12 +3,10 @@ windows_subsystem = "windows" )] -#[cfg(target_os = "macos")] -extern crate cocoa; - #[cfg(target_os = "macos")] use border::WebviewWindowExt as BorderWebviewWindowExt; use commands::{account::*, event::*, metadata::*, relay::*, window::*}; +use common::parse_event; use nostr_sdk::prelude::*; use serde::{Deserialize, Serialize}; use specta::Type; @@ -17,21 +15,18 @@ use std::{ fs, io::{self, BufRead}, str::FromStr, - sync::Mutex, time::Duration, }; -use tauri::{path::BaseDirectory, Manager}; +use tauri::{path::BaseDirectory, Emitter, EventTarget, Manager}; use tauri_plugin_decorum::WebviewWindowExt; -use tauri_specta::{collect_commands, Builder}; +use tauri_plugin_notification::{NotificationExt, PermissionState}; +use tauri_specta::{collect_commands, collect_events, Builder, Event as TauriEvent}; +use tokio::sync::Mutex; pub mod commands; pub mod common; -#[cfg(target_os = "macos")] -pub mod macos; -#[derive(Serialize)] pub struct Nostr { - #[serde(skip_serializing)] client: Client, contact_list: Mutex>, settings: Mutex, @@ -47,28 +42,45 @@ pub struct Settings { display_zap_button: bool, display_repost_button: bool, display_media: bool, - vibrancy: bool, + transparent: bool, } impl Default for Settings { fn default() -> Self { Self { proxy: None, - image_resize_service: Some("https://wsrv.nl/".into()), + image_resize_service: Some("https://wsrv.nl".to_string()), use_relay_hint: true, content_warning: true, display_avatar: true, display_zap_button: true, display_repost_button: true, display_media: true, - vibrancy: true, + transparent: true, } } } -pub const FETCH_LIMIT: usize = 20; +#[derive(Serialize, Deserialize, Type)] +enum SubKind { + Subscribe, + Unsubscribe, +} + +#[derive(Serialize, Deserialize, Type, TauriEvent)] +struct Subscription { + label: String, + kind: SubKind, + event_id: Option, +} + +#[derive(Serialize, Deserialize, Type, Clone, TauriEvent)] +struct NewSettings(Settings); + +pub const FETCH_LIMIT: usize = 44; pub const NEWSFEED_NEG_LIMIT: usize = 256; pub const NOTIFICATION_NEG_LIMIT: usize = 64; +pub const NOTIFICATION_SUB_ID: &str = "lume_notification"; fn main() { let builder = Builder::::new() @@ -83,54 +95,57 @@ fn main() { create_account, import_account, connect_account, + get_private_key, delete_account, + reset_password, login, get_profile, + set_profile, get_contact_list, set_contact_list, - create_profile, is_contact_list_empty, check_contact, toggle_contact, - get_nstore, - set_nstore, + get_lume_store, + set_lume_store, set_wallet, load_wallet, remove_wallet, zap_profile, zap_event, - friend_to_friend, + copy_friend, get_notifications, get_settings, - set_new_settings, + set_settings, verify_nip05, get_event_meta, get_event, get_event_from, get_replies, - listen_event_reply, + subscribe_to, get_events_by, - get_local_events, - listen_local_event, + get_events_from_contacts, get_group_events, get_global_events, get_hashtag_events, + search, publish, reply, repost, event_to_bech32, user_to_bech32, - unlisten, create_column, close_column, reposition_column, resize_column, reload_column, open_window, - open_main_window, - force_quit - ]); + reopen_lume, + quit + ]) + .events(collect_events![Subscription, NewSettings]); + #[cfg(debug_assertions)] builder .export(Typescript::default(), "../src/commands.gen.ts") .expect("Failed to export typescript bindings"); @@ -148,10 +163,9 @@ fn main() { .setup(move |app| { builder.mount_events(app); - #[cfg(target_os = "macos")] - app.handle().plugin(tauri_nspanel::init()).unwrap(); - let handle = app.handle(); + let handle_clone = handle.clone(); + let handle_clone_child = handle_clone.clone(); let main_window = app.get_webview_window("main").unwrap(); // Set custom decoration for Windows @@ -164,7 +178,7 @@ fn main() { // Set a custom inset to the traffic lights #[cfg(target_os = "macos")] - main_window.set_traffic_lights_inset(8.0, 16.0).unwrap(); + main_window.set_traffic_lights_inset(7.0, 10.0).unwrap(); #[cfg(target_os = "macos")] let win = main_window.clone(); @@ -172,25 +186,29 @@ fn main() { #[cfg(target_os = "macos")] main_window.on_window_event(move |event| { if let tauri::WindowEvent::ThemeChanged(_) = event { - win.set_traffic_lights_inset(8.0, 16.0).unwrap(); + win.set_traffic_lights_inset(7.0, 10.0).unwrap(); } }); - // Create data folder if not exist - let home_dir = app.path().home_dir().unwrap(); - let _ = fs::create_dir_all(home_dir.join("Lume/")); - let client = tauri::async_runtime::block_on(async move { + // Create data folder if not exist + let dir = handle + .path() + .app_config_dir() + .expect("App config directory not found."); + let _ = fs::create_dir_all(dir.clone()); + // Setup database - let database = SQLiteDatabase::open(home_dir.join("Lume/lume.db")) + let database = SQLiteDatabase::open(dir.join("nostr.db")) .await - .expect("Error."); + .expect("Database error."); // Config let opts = Options::new() + .max_avg_latency(Duration::from_millis(500)) .automatic_authentication(true) .connection_timeout(Some(Duration::from_secs(5))) - .timeout(Duration::from_secs(30)); + .timeout(Duration::from_secs(20)); // Setup nostr client let client = ClientBuilder::default() @@ -211,10 +229,6 @@ fn main() { if let Some((relay, option)) = line.split_once(',') { match RelayMetadata::from_str(option) { Ok(meta) => { - println!( - "connecting to bootstrap relay...: {} - {}", - relay, meta - ); let opts = if meta == RelayMetadata::Read { RelayOptions::new().read(true).write(false) } else { @@ -223,7 +237,6 @@ fn main() { let _ = client.add_relay_with_opts(relay, opts).await; } Err(_) => { - println!("connecting to bootstrap relay...: {}", relay); let _ = client.add_relay(relay).await; } } @@ -244,11 +257,116 @@ fn main() { settings: Mutex::new(Settings::default()), }); + Subscription::listen_any(app, move |event| { + let handle = handle_clone_child.to_owned(); + let payload = event.payload; + + tauri::async_runtime::spawn(async move { + let state = handle.state::(); + let client = &state.client; + + match payload.kind { + SubKind::Subscribe => { + let subscription_id = SubscriptionId::new(payload.label); + + let filter = if let Some(id) = payload.event_id { + let event_id = EventId::from_str(&id).unwrap(); + + Filter::new().event(event_id).since(Timestamp::now()) + } else { + let contact_list = state.contact_list.lock().await; + let authors: Vec = + contact_list.iter().map(|f| f.public_key).collect(); + + Filter::new() + .kinds(vec![Kind::TextNote, Kind::Repost]) + .authors(authors) + .since(Timestamp::now()) + }; + + if let Err(e) = client + .subscribe_with_id(subscription_id, vec![filter], None) + .await + { + println!("Subscription error: {}", e) + } + } + SubKind::Unsubscribe => { + let subscription_id = SubscriptionId::new(payload.label); + client.unsubscribe(subscription_id).await + } + } + }); + }); + + tauri::async_runtime::spawn(async move { + let state = handle_clone.state::(); + let client = &state.client; + + let allow_notification = match handle_clone.notification().request_permission() { + Ok(_) => { + if let Ok(perm) = handle_clone.notification().permission_state() { + PermissionState::Granted == perm + } else { + false + } + } + Err(_) => false, + }; + + let notification_id = SubscriptionId::new(NOTIFICATION_SUB_ID); + + client + .handle_notifications(|notification| async { + if let RelayPoolNotification::Message { message, .. } = notification { + if let RelayMessage::Event { + subscription_id, + event, + } = message + { + // Handle events from notification subscription + if subscription_id == notification_id { + // Send native notification + if allow_notification { + let author = client + .metadata(event.pubkey) + .await + .unwrap_or_else(|_| Metadata::new()); + + send_notification(&event, author, &handle_clone); + } + } + + let label = subscription_id.to_string(); + let raw = event.as_json(); + let parsed = if event.kind == Kind::TextNote { + Some(parse_event(&event.content).await) + } else { + None + }; + + handle_clone + .emit_to( + EventTarget::labeled(label), + "event", + RichEvent { raw, parsed }, + ) + .unwrap(); + } else { + println!("new message: {}", message.as_json()) + } + } + Ok(false) + }) + .await + }); + Ok(()) }) - .plugin(tauri_plugin_prevent_default::init()) + .plugin(prevent_default()) .plugin(tauri_plugin_theme::init(ctx.config_mut())) .plugin(tauri_plugin_decorum::init()) + .plugin(tauri_plugin_store::Builder::default().build()) .plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_fs::init()) @@ -262,3 +380,56 @@ fn main() { .run(ctx) .expect("error while running tauri application"); } + +#[cfg(debug_assertions)] +fn prevent_default() -> tauri::plugin::TauriPlugin { + use tauri_plugin_prevent_default::Flags; + + tauri_plugin_prevent_default::Builder::new() + .with_flags(Flags::all().difference(Flags::CONTEXT_MENU)) + .build() +} + +#[cfg(not(debug_assertions))] +fn prevent_default() -> tauri::plugin::TauriPlugin { + tauri_plugin_prevent_default::Builder::new().build() +} + +fn send_notification(event: &Event, author: Metadata, handle: &tauri::AppHandle) { + match event.kind() { + Kind::TextNote => { + if let Err(e) = handle + .notification() + .builder() + .body("Mentioned you in a thread.") + .title(author.display_name.unwrap_or_else(|| "Lume".to_string())) + .show() + { + println!("Error: {}", e); + } + } + Kind::Repost => { + if let Err(e) = handle + .notification() + .builder() + .body("Reposted your note.") + .title(author.display_name.unwrap_or_else(|| "Lume".to_string())) + .show() + { + println!("Error: {}", e); + } + } + Kind::ZapReceipt => { + if let Err(e) = handle + .notification() + .builder() + .body("Zapped you.") + .title(author.display_name.unwrap_or_else(|| "Lume".to_string())) + .show() + { + println!("Error: {}", e); + } + } + _ => {} + } +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c91f0c37..e14aec5f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -33,7 +33,6 @@ } }, "bundle": { - "licenseFile": "../LICENSE", "homepage": "https://lume.nu", "longDescription": "nostr client for desktop", "shortDescription": "nostr client", @@ -61,21 +60,6 @@ "macOS": { "minimumSystemVersion": "10.15" }, - "fileAssociations": [ - { - "name": "bech32", - "description": "Nostr BECH32", - "ext": [ - "npub", - "nsec", - "nprofile", - "nevent", - "naddr", - "nrelay" - ], - "role": "Viewer" - } - ], "createUpdaterArtifacts": true }, "plugins": { diff --git a/src/app.css b/src/app.css index 7ab845ca..56cded81 100644 --- a/src/app.css +++ b/src/app.css @@ -50,11 +50,11 @@ input::-ms-clear { } div[data-tauri-decorum-tb] { - @apply h-11 !important; + @apply h-10 !important; } button.decorum-tb-btn { - @apply h-11 !important; + @apply h-10 !important; } .spinner-leaf { diff --git a/src/app.tsx b/src/app.tsx index 4d99e2d7..c468d89f 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,13 +1,31 @@ +import { + type PersistedQuery, + experimental_createPersister, +} from "@tanstack/query-persist-client-core"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { RouterProvider, createRouter } from "@tanstack/react-router"; import { type } from "@tauri-apps/plugin-os"; import { StrictMode } from "react"; import ReactDOM from "react-dom/client"; +import { newQueryStorage } from "./commons"; import { routeTree } from "./routes.gen"; // auto generated file +import type { LumeEvent } from "./system"; import "./app.css"; +import { Store } from "@tauri-apps/plugin-store"; -const queryClient = new QueryClient(); const platform = type(); +const tauriStore = new Store(".lume.dat"); +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + gcTime: 1000 * 30, + persister: experimental_createPersister({ + storage: newQueryStorage(tauriStore), + maxAge: 1000 * 60 * 60 * 24, // 24 hours, + }), + }, + }, +}); const router = createRouter({ routeTree, @@ -24,6 +42,9 @@ declare module "@tanstack/react-router" { interface Register { router: typeof router; } + interface HistoryState { + events?: LumeEvent[]; + } } function App() { diff --git a/src/commands.gen.ts b/src/commands.gen.ts index d007bb45..28294267 100644 --- a/src/commands.gen.ts +++ b/src/commands.gen.ts @@ -72,6 +72,14 @@ async connectAccount(uri: string) : Promise> { else return { status: "error", error: e as any }; } }, +async getPrivateKey(id: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_private_key", { id }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, async deleteAccount(id: string) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("delete_account", { id }) }; @@ -80,6 +88,14 @@ async deleteAccount(id: string) : Promise> { else return { status: "error", error: e as any }; } }, +async resetPassword(key: string, password: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("reset_password", { key, password }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, async login(account: string, password: string) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("login", { account, password }) }; @@ -96,6 +112,14 @@ async getProfile(id: string | null) : Promise> { else return { status: "error", error: e as any }; } }, +async setProfile(profile: Profile) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_profile", { profile }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, async getContactList() : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("get_contact_list") }; @@ -112,14 +136,6 @@ async setContactList(publicKeys: string[]) : Promise> { else return { status: "error", error: e as any }; } }, -async createProfile(name: string, displayName: string, about: string, picture: string, banner: string, nip05: string, lud16: string, website: string) : Promise> { - try { - return { status: "ok", data: await TAURI_INVOKE("create_profile", { name, displayName, about, picture, banner, nip05, lud16, website }) }; -} catch (e) { - if(e instanceof Error) throw e; - else return { status: "error", error: e as any }; -} -}, async isContactListEmpty() : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("is_contact_list_empty") }; @@ -136,25 +152,25 @@ async checkContact(hex: string) : Promise> { else return { status: "error", error: e as any }; } }, -async toggleContact(hex: string, alias: string | null) : Promise> { +async toggleContact(id: string, alias: string | null) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("toggle_contact", { hex, alias }) }; + return { status: "ok", data: await TAURI_INVOKE("toggle_contact", { id, alias }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } }, -async getNstore(key: string) : Promise> { +async getLumeStore(key: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("get_nstore", { key }) }; + return { status: "ok", data: await TAURI_INVOKE("get_lume_store", { key }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } }, -async setNstore(key: string, content: string) : Promise> { +async setLumeStore(key: string, content: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("set_nstore", { key, content }) }; + return { status: "ok", data: await TAURI_INVOKE("set_lume_store", { key, content }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; @@ -200,9 +216,9 @@ async zapEvent(id: string, amount: string, message: string) : Promise> { +async copyFriend(npub: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("friend_to_friend", { npub }) }; + return { status: "ok", data: await TAURI_INVOKE("copy_friend", { npub }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; @@ -224,17 +240,17 @@ async getSettings() : Promise> { else return { status: "error", error: e as any }; } }, -async setNewSettings(settings: string) : Promise> { +async setSettings(settings: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("set_new_settings", { settings }) }; + return { status: "ok", data: await TAURI_INVOKE("set_settings", { settings }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } }, -async verifyNip05(key: string, nip05: string) : Promise> { +async verifyNip05(id: string, nip05: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("verify_nip05", { key, nip05 }) }; + return { status: "ok", data: await TAURI_INVOKE("verify_nip05", { id, nip05 }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; @@ -272,33 +288,25 @@ async getReplies(id: string) : Promise> { else return { status: "error", error: e as any }; } }, -async listenEventReply(id: string) : Promise> { +async subscribeTo(id: string) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("listen_event_reply", { id }) }; + return { status: "ok", data: await TAURI_INVOKE("subscribe_to", { id }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } }, -async getEventsBy(publicKey: string, asOf: string | null) : Promise> { +async getEventsBy(publicKey: string, limit: number) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("get_events_by", { publicKey, asOf }) }; + return { status: "ok", data: await TAURI_INVOKE("get_events_by", { publicKey, limit }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } }, -async getLocalEvents(until: string | null) : Promise> { +async getEventsFromContacts(until: string | null) : Promise> { try { - return { status: "ok", data: await TAURI_INVOKE("get_local_events", { until }) }; -} catch (e) { - if(e instanceof Error) throw e; - else return { status: "error", error: e as any }; -} -}, -async listenLocalEvent(label: string) : Promise> { - try { - return { status: "ok", data: await TAURI_INVOKE("listen_local_event", { label }) }; + return { status: "ok", data: await TAURI_INVOKE("get_events_from_contacts", { until }) }; } catch (e) { if(e instanceof Error) throw e; else return { status: "error", error: e as any }; @@ -328,6 +336,14 @@ async getHashtagEvents(hashtags: string[], until: string | null) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("search", { query, until }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, async publish(content: string, warning: string | null, difficulty: number | null) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("publish", { content, warning, difficulty }) }; @@ -368,14 +384,6 @@ async userToBech32(user: string) : Promise> { else return { status: "error", error: e as any }; } }, -async unlisten(id: string) : Promise> { - try { - return { status: "ok", data: await TAURI_INVOKE("unlisten", { id }) }; -} catch (e) { - if(e instanceof Error) throw e; - else return { status: "error", error: e as any }; -} -}, async createColumn(column: Column) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("create_column", { column }) }; @@ -392,7 +400,7 @@ async closeColumn(label: string) : Promise> { else return { status: "error", error: e as any }; } }, -async repositionColumn(label: string, x: number, y: number) : Promise> { +async repositionColumn(label: string, x: number, y: number) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("reposition_column", { label, x, y }) }; } catch (e) { @@ -400,7 +408,7 @@ async repositionColumn(label: string, x: number, y: number) : Promise> { +async resizeColumn(label: string, width: number, height: number) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("resize_column", { label, width, height }) }; } catch (e) { @@ -408,7 +416,7 @@ async resizeColumn(label: string, width: number, height: number) : Promise> { +async reloadColumn(label: string) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("reload_column", { label }) }; } catch (e) { @@ -424,17 +432,24 @@ async openWindow(window: Window) : Promise> { else return { status: "error", error: e as any }; } }, -async openMainWindow() : Promise { - await TAURI_INVOKE("open_main_window"); +async reopenLume() : Promise { + await TAURI_INVOKE("reopen_lume"); }, -async forceQuit() : Promise { - await TAURI_INVOKE("force_quit"); +async quit() : Promise { + await TAURI_INVOKE("quit"); } } /** user-defined events **/ +export const events = __makeEvents__<{ +newSettings: NewSettings, +subscription: Subscription +}>({ +newSettings: "new-settings", +subscription: "subscription" +}) /** user-defined constants **/ @@ -444,9 +459,13 @@ async forceQuit() : Promise { export type Column = { label: string; url: string; x: number; y: number; width: number; height: number } export type Meta = { content: string; images: string[]; videos: string[]; events: string[]; mentions: string[]; hashtags: string[] } +export type NewSettings = Settings +export type Profile = { name: string; display_name: string; about: string | null; picture: string; banner: string | null; nip05: string | null; lud16: string | null; website: string | null } export type Relays = { connected: string[]; read: string[] | null; write: string[] | null; both: string[] | null } export type RichEvent = { raw: string; parsed: Meta | null } -export type Settings = { proxy: string | null; image_resize_service: string | null; use_relay_hint: boolean; content_warning: boolean; display_avatar: boolean; display_zap_button: boolean; display_repost_button: boolean; display_media: boolean; vibrancy: boolean } +export type Settings = { proxy: string | null; image_resize_service: string | null; use_relay_hint: boolean; content_warning: boolean; display_avatar: boolean; display_zap_button: boolean; display_repost_button: boolean; display_media: boolean; transparent: boolean } +export type SubKind = "Subscribe" | "Unsubscribe" +export type Subscription = { label: string; kind: SubKind; event_id: string | null } export type Window = { label: string; title: string; url: string; width: number; height: number; maximizable: boolean; minimizable: boolean; hidden_title: boolean } /** tauri-specta globals **/ diff --git a/src/commons.ts b/src/commons.ts index eb189045..8c797795 100644 --- a/src/commons.ts +++ b/src/commons.ts @@ -1,6 +1,12 @@ -import type { Contact } from "@/types"; +import type { + AsyncStorage, + MaybePromise, + PersistedQuery, +} from "@tanstack/query-persist-client-core"; +import { Store } from "@tanstack/store"; import { ask, message } from "@tauri-apps/plugin-dialog"; import { relaunch } from "@tauri-apps/plugin-process"; +import type { Store as TauriStore } from "@tauri-apps/plugin-store"; import { check } from "@tauri-apps/plugin-updater"; import { BitcoinUnit } from "bitcoin-units"; import { type ClassValue, clsx } from "clsx"; @@ -8,12 +14,12 @@ import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; import updateLocale from "dayjs/plugin/updateLocale"; import { decode } from "light-bolt11-decoder"; -import type { ReactNode } from "react"; -import ReactDOM from "react-dom"; import { type BaseEditor, Transforms } from "slate"; import { ReactEditor } from "slate-react"; import { twMerge } from "tailwind-merge"; -import { AUDIOS, IMAGES, VIDEOS } from "./constants"; +import type { RichEvent, Settings } from "./commands.gen"; +import { LumeEvent } from "./system"; +import type { NostrEvent } from "./types"; dayjs.extend(relativeTime); dayjs.extend(updateLocale); @@ -35,12 +41,6 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export const Portal = ({ children }: { children?: ReactNode }) => { - return typeof document === "object" - ? ReactDOM.createPortal(children, document.body) - : null; -}; - export const isImagePath = (path: string) => { for (const suffix of ["jpg", "jpeg", "gif", "png", "webp", "avif", "tiff"]) { if (path.endsWith(suffix)) return true; @@ -127,24 +127,17 @@ export function formatCreatedAt(time: number, message = false) { return formated; } -export function displayNsec(key: string, len: number) { - if (key.length <= len) return key; +export function replyTime(time: number) { + const inputTime = dayjs.unix(time); + const formated = inputTime.format("MM-DD-YY HH:mm"); - const separator = " ... "; - - const sepLen = separator.length; - const charsToShow = len - sepLen; - const frontChars = Math.ceil(charsToShow / 2); - const backChars = Math.floor(charsToShow / 2); - - return ( - key.substr(0, frontChars) + separator + key.substr(key.length - backChars) - ); + return formated; } export function displayNpub(pubkey: string, len: number) { if (pubkey.length <= len) return pubkey; + const str = pubkey.replace("nostr:", ""); const separator = " ... "; const sepLen = separator.length; @@ -153,9 +146,9 @@ export function displayNpub(pubkey: string, len: number) { const backChars = Math.floor(charsToShow / 2); return ( - pubkey.substr(0, frontChars) + + str.substring(0, frontChars) + separator + - pubkey.substr(pubkey.length - backChars) + str.substring(str.length - backChars) ); } @@ -167,32 +160,6 @@ export function displayLongHandle(str: string) { return `${handle.substring(0, 16)}...@${service}`; } -// convert number to K, M, B, T, etc. -export const compactNumber = Intl.NumberFormat("en", { notation: "compact" }); - -// country name -export const regionNames = new Intl.DisplayNames(["en"], { type: "language" }); - -// verify link can be preview -export function canPreview(text: string) { - const url = new URL(text); - const ext = url.pathname.split(".").pop(); - const hostname = url.hostname; - - if (VIDEOS.includes(ext)) return false; - if (IMAGES.includes(ext)) return false; - if (AUDIOS.includes(ext)) return false; - - if (hostname === "youtube.com") return false; - if (hostname === "youtu.be") return false; - if (hostname === "x.com") return false; - if (hostname === "twitter.com") return false; - if (hostname === "facebook.com") return false; - if (hostname === "vimeo.com") return false; - - return true; -} - // source: https://github.com/synonymdev/bitkit/blob/master/src/utils/displayValues/index.ts export function getBitcoinDisplayValues(satoshis: number) { let bitcoinFormatted = new BitcoinUnit(satoshis, "satoshis") @@ -273,3 +240,44 @@ export async function checkForAppUpdates(silent: boolean) { return; } } + +export function toLumeEvents(richEvents: RichEvent[]) { + const events = richEvents.map((item) => { + const nostrEvent: NostrEvent = JSON.parse(item.raw); + + if (item.parsed) { + nostrEvent.meta = item.parsed; + } else { + nostrEvent.meta = null; + } + + const lumeEvent = new LumeEvent(nostrEvent); + + return lumeEvent; + }); + + return events; +} + +export function newQueryStorage( + store: TauriStore, +): AsyncStorage { + return { + getItem: async (key) => await store.get(key), + setItem: async (key, value) => await store.set(key, value), + removeItem: async (key) => + (await store.delete(key)) as unknown as MaybePromise, + }; +} + +export const appSettings = new Store({ + proxy: null, + image_resize_service: "https://wsrv.nl", + use_relay_hint: true, + content_warning: true, + display_avatar: true, + display_zap_button: true, + display_repost_button: true, + display_media: true, + transparent: true, +}); diff --git a/src/components/avatarUploader.tsx b/src/components/avatarUploader.tsx deleted file mode 100644 index 02fdce04..00000000 --- a/src/components/avatarUploader.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { cn } from "@/commons"; -import { Spinner } from "@/components"; -import { NostrQuery } from "@/system"; -import { message } from "@tauri-apps/plugin-dialog"; -import { - type Dispatch, - type ReactNode, - type SetStateAction, - useState, -} from "react"; - -export function AvatarUploader({ - setPicture, - children, - className, -}: { - setPicture: Dispatch>; - children: ReactNode; - className?: string; -}) { - const [loading, setLoading] = useState(false); - - const uploadAvatar = async () => { - try { - setLoading(true); - const image = await NostrQuery.upload(); - setPicture(image); - } catch (e) { - setLoading(false); - await message(String(e), { title: "Lume", kind: "error" }); - } - }; - - return ( - - ); -} diff --git a/src/components/box.tsx b/src/components/box.tsx deleted file mode 100644 index 1228b08c..00000000 --- a/src/components/box.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { cn } from "@/commons"; -import type { ReactNode } from "react"; - -export function Box({ - children, - className, -}: { - children: ReactNode; - className?: string; -}) { - return ( -
-
-
- {children} -
-
-
- ); -} diff --git a/src/components/column.tsx b/src/components/column.tsx index f21e00fb..fc686acc 100644 --- a/src/components/column.tsx +++ b/src/components/column.tsx @@ -1,29 +1,29 @@ -import { CheckIcon, HorizontalDotsIcon } from "@/components"; +import { commands } from "@/commands.gen"; import type { LumeColumn } from "@/types"; +import { Check, DotsThree } from "@phosphor-icons/react"; +import { useParams } from "@tanstack/react-router"; import { invoke } from "@tauri-apps/api/core"; import { listen } from "@tauri-apps/api/event"; import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu"; import { getCurrentWindow } from "@tauri-apps/api/window"; import { memo, useCallback, useEffect, useRef, useState } from "react"; +import { Spinner } from "./spinner"; type WindowEvent = { scroll: boolean; resize: boolean; }; -export const Column = memo(function Column({ - column, - account, -}: { - column: LumeColumn; - account: string; -}) { +export const Column = memo(function Column({ column }: { column: LumeColumn }) { + const params = useParams({ strict: false }); const container = useRef(null); - const webviewLabel = `column-${account}_${column.label}`; + const webviewLabel = `column-${params.account}_${column.label}`; const [isCreated, setIsCreated] = useState(false); const repositionWebview = useCallback(async () => { + if (!container.current) return; + const newRect = container.current.getBoundingClientRect(); await invoke("reposition_column", { label: webviewLabel, @@ -33,6 +33,8 @@ export const Column = memo(function Column({ }, []); const resizeWebview = useCallback(async () => { + if (!container.current) return; + const newRect = container.current.getBoundingClientRect(); await invoke("resize_column", { label: webviewLabel, @@ -55,10 +57,10 @@ export const Column = memo(function Column({ }, [isCreated]); useEffect(() => { - if (!container?.current) return; + if (!container.current) return; const rect = container.current.getBoundingClientRect(); - const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`; + const url = `${column.url}?account=${params.account}&label=${column.label}&name=${column.name}`; const prop = { label: webviewLabel, @@ -81,27 +83,25 @@ export const Column = memo(function Column({ console.log("closed: ", webviewLabel); }); }; - }, [account]); + }, [params.account]); return (
-
-
-
+
+
+
+ {!isCreated ? ( +
+ +
+ ) : null} +
); }); -function Header({ - label, - webview, - name, -}: { label: string; webview: string; name: string }) { +function Header({ label, name }: { label: string; name: string }) { const [title, setTitle] = useState(name); const [isChanged, setIsChanged] = useState(false); @@ -120,11 +120,12 @@ function Header({ const showContextMenu = useCallback(async (e: React.MouseEvent) => { e.preventDefault(); + const window = getCurrentWindow(); const menuItems = await Promise.all([ MenuItem.new({ text: "Reload", action: async () => { - await invoke("reload_column", { label: webview }); + await commands.reloadColumn(label); }, }), MenuItem.new({ @@ -135,7 +136,7 @@ function Header({ MenuItem.new({ text: "Move left", action: async () => { - await getCurrentWindow().emit("columns", { + await window.emit("columns", { type: "move", label, direction: "left", @@ -145,7 +146,7 @@ function Header({ MenuItem.new({ text: "Move right", action: async () => { - await getCurrentWindow().emit("columns", { + await window.emit("columns", { type: "move", label, direction: "right", @@ -156,7 +157,7 @@ function Header({ MenuItem.new({ text: "Close", action: async () => { - await getCurrentWindow().emit("columns", { + await window.emit("columns", { type: "remove", label, }); @@ -194,7 +195,7 @@ function Header({ onClick={() => saveNewTitle()} className="text-teal-500 hover:text-teal-600" > - + ) : null}
@@ -204,7 +205,7 @@ function Header({ onClick={(e) => showContextMenu(e)} className="inline-flex items-center justify-center rounded-lg size-7 hover:bg-black/10 dark:hover:bg-white/10" > - +
); diff --git a/src/components/container.tsx b/src/components/container.tsx deleted file mode 100644 index 44ddce47..00000000 --- a/src/components/container.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { cn } from "@/commons"; -import type { ReactNode } from "react"; - -export function Container({ - children, - withDrag = false, - className, -}: { - children: ReactNode; - withDrag?: boolean; - className?: string; -}) { - return ( -
- {withDrag ? ( -
- ) : null} - {children} -
- ); -} diff --git a/src/components/conversation.tsx b/src/components/conversation.tsx index 316957c7..09ed64e6 100644 --- a/src/components/conversation.tsx +++ b/src/components/conversation.tsx @@ -1,7 +1,7 @@ import { cn } from "@/commons"; -import { ThreadIcon } from "@/components"; import { Note } from "@/components/note"; import type { LumeEvent } from "@/system"; +import { ChatsTeardrop } from "@phosphor-icons/react"; import { memo, useMemo } from "react"; export const Conversation = memo(function Conversation({ @@ -25,7 +25,7 @@ export const Conversation = memo(function Conversation({ {thread?.root?.id ? : null}
- + Thread
diff --git a/src/components/icons/addMedia.tsx b/src/components/icons/addMedia.tsx deleted file mode 100644 index 94a15523..00000000 --- a/src/components/icons/addMedia.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function AddMediaIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/addWidget.tsx b/src/components/icons/addWidget.tsx deleted file mode 100644 index e03fc8e3..00000000 --- a/src/components/icons/addWidget.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function AddWidgetIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/advancedSettings.tsx b/src/components/icons/advancedSettings.tsx deleted file mode 100644 index 37657738..00000000 --- a/src/components/icons/advancedSettings.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function AdvancedSettingsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/alby.tsx b/src/components/icons/alby.tsx deleted file mode 100644 index 8a88ddaa..00000000 --- a/src/components/icons/alby.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import type { SVGProps } from "react"; - -export function AlbyIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - - - - - - - - - - - - ); -} diff --git a/src/components/icons/announcement.tsx b/src/components/icons/announcement.tsx deleted file mode 100644 index 898cfb43..00000000 --- a/src/components/icons/announcement.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function AnnouncementIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/antenas.tsx b/src/components/icons/antenas.tsx deleted file mode 100644 index cf9efb8c..00000000 --- a/src/components/icons/antenas.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function AntenasIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowDown.tsx b/src/components/icons/arrowDown.tsx deleted file mode 100644 index 90a35957..00000000 --- a/src/components/icons/arrowDown.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ArrowDownIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowLeft.tsx b/src/components/icons/arrowLeft.tsx deleted file mode 100644 index 33ef7953..00000000 --- a/src/components/icons/arrowLeft.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function ArrowLeftIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowRight.tsx b/src/components/icons/arrowRight.tsx deleted file mode 100644 index e526a57b..00000000 --- a/src/components/icons/arrowRight.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function ArrowRightIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowRightCircle.tsx b/src/components/icons/arrowRightCircle.tsx deleted file mode 100644 index 8c8c8511..00000000 --- a/src/components/icons/arrowRightCircle.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ArrowRightCircleIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowUp.tsx b/src/components/icons/arrowUp.tsx deleted file mode 100644 index 5ac6a634..00000000 --- a/src/components/icons/arrowUp.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ArrowUpIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/arrowUpSquare.tsx b/src/components/icons/arrowUpSquare.tsx deleted file mode 100644 index 4270b5e2..00000000 --- a/src/components/icons/arrowUpSquare.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ArrowUpSquareIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/article.tsx b/src/components/icons/article.tsx deleted file mode 100644 index f63d521b..00000000 --- a/src/components/icons/article.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { SVGProps } from "react"; - -export function ArticleIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/bell.tsx b/src/components/icons/bell.tsx deleted file mode 100644 index ade9bcca..00000000 --- a/src/components/icons/bell.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { SVGProps } from "react"; - -export function BellIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/bellFilled.tsx b/src/components/icons/bellFilled.tsx deleted file mode 100644 index bed85427..00000000 --- a/src/components/icons/bellFilled.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function BellFilledIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/bold.tsx b/src/components/icons/bold.tsx deleted file mode 100644 index 04b2729b..00000000 --- a/src/components/icons/bold.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function BoldIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/cancel.tsx b/src/components/icons/cancel.tsx deleted file mode 100644 index 6e3e1d78..00000000 --- a/src/components/icons/cancel.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function CancelIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/cancelCircle.tsx b/src/components/icons/cancelCircle.tsx deleted file mode 100644 index 0be4c042..00000000 --- a/src/components/icons/cancelCircle.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function CancelCircleIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/chats.tsx b/src/components/icons/chats.tsx deleted file mode 100644 index 7f3ac32d..00000000 --- a/src/components/icons/chats.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ChatsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/check.tsx b/src/components/icons/check.tsx deleted file mode 100644 index 78c4c700..00000000 --- a/src/components/icons/check.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function CheckIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/checkCircle.tsx b/src/components/icons/checkCircle.tsx deleted file mode 100644 index 91084c7b..00000000 --- a/src/components/icons/checkCircle.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function CheckCircleIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/chevronDown.tsx b/src/components/icons/chevronDown.tsx deleted file mode 100644 index 39d41102..00000000 --- a/src/components/icons/chevronDown.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { SVGProps } from "react"; - -export function ChevronDownIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/chevronRight.tsx b/src/components/icons/chevronRight.tsx deleted file mode 100644 index a41bfa0b..00000000 --- a/src/components/icons/chevronRight.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ChevronRightIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/chevronUp.tsx b/src/components/icons/chevronUp.tsx deleted file mode 100644 index 81741117..00000000 --- a/src/components/icons/chevronUp.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ChevronUpIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/cmd.tsx b/src/components/icons/cmd.tsx deleted file mode 100644 index a92defcd..00000000 --- a/src/components/icons/cmd.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { SVGProps } from "react"; - -export function CommandIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/column.tsx b/src/components/icons/column.tsx deleted file mode 100644 index d8ebc1b9..00000000 --- a/src/components/icons/column.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function ColumnIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/community.tsx b/src/components/icons/community.tsx deleted file mode 100644 index e99fe33c..00000000 --- a/src/components/icons/community.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function CommunityIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/compose.tsx b/src/components/icons/compose.tsx deleted file mode 100644 index 9f303c47..00000000 --- a/src/components/icons/compose.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ComposeIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/composeFilled.tsx b/src/components/icons/composeFilled.tsx deleted file mode 100644 index ef37dd90..00000000 --- a/src/components/icons/composeFilled.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function ComposeFilledIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/copy.tsx b/src/components/icons/copy.tsx deleted file mode 100644 index 71bf973f..00000000 --- a/src/components/icons/copy.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function CopyIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/dark.tsx b/src/components/icons/dark.tsx deleted file mode 100644 index ea627ee3..00000000 --- a/src/components/icons/dark.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function DarkIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/depot.tsx b/src/components/icons/depot.tsx deleted file mode 100644 index 7c15e544..00000000 --- a/src/components/icons/depot.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function DepotIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/depotFilled.tsx b/src/components/icons/depotFilled.tsx deleted file mode 100644 index 205ce941..00000000 --- a/src/components/icons/depotFilled.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function DepotFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/dots.tsx b/src/components/icons/dots.tsx deleted file mode 100644 index 13645464..00000000 --- a/src/components/icons/dots.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { SVGProps } from "react"; - -export function DotsPattern( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - - - ); -} diff --git a/src/components/icons/download.tsx b/src/components/icons/download.tsx deleted file mode 100644 index ddd5839b..00000000 --- a/src/components/icons/download.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { SVGProps } from "react"; - -export function DownloadIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/edit.tsx b/src/components/icons/edit.tsx deleted file mode 100644 index 33882ff0..00000000 --- a/src/components/icons/edit.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function EditIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/editInterest.tsx b/src/components/icons/editInterest.tsx deleted file mode 100644 index 06f14ca1..00000000 --- a/src/components/icons/editInterest.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function EditInterestIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/empty.tsx b/src/components/icons/empty.tsx deleted file mode 100644 index b63f7e9d..00000000 --- a/src/components/icons/empty.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import type { SVGProps } from "react"; - -export function EmptyIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/components/icons/enter.tsx b/src/components/icons/enter.tsx deleted file mode 100644 index c35b2a2b..00000000 --- a/src/components/icons/enter.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function EnterIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/expand.tsx b/src/components/icons/expand.tsx deleted file mode 100644 index f4bc08dc..00000000 --- a/src/components/icons/expand.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { SVGProps } from "react"; - -export function ExpandIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/explore.tsx b/src/components/icons/explore.tsx deleted file mode 100644 index ad763f89..00000000 --- a/src/components/icons/explore.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { SVGProps } from "react"; - -export function ExploreIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - - - - - - - ); -} diff --git a/src/components/icons/explore2.tsx b/src/components/icons/explore2.tsx deleted file mode 100644 index 5c329722..00000000 --- a/src/components/icons/explore2.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { SVGProps } from "react"; - -export function Explore2Icon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/eyeOff.tsx b/src/components/icons/eyeOff.tsx deleted file mode 100644 index 598ad31e..00000000 --- a/src/components/icons/eyeOff.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function EyeOffIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/eyeOn.tsx b/src/components/icons/eyeOn.tsx deleted file mode 100644 index b9d35401..00000000 --- a/src/components/icons/eyeOn.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function EyeOnIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/feed.tsx b/src/components/icons/feed.tsx deleted file mode 100644 index 6bc35b72..00000000 --- a/src/components/icons/feed.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function FeedIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/file.tsx b/src/components/icons/file.tsx deleted file mode 100644 index 0125de25..00000000 --- a/src/components/icons/file.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { SVGProps } from "react"; - -export function FileIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/focus.tsx b/src/components/icons/focus.tsx deleted file mode 100644 index 405ac0ee..00000000 --- a/src/components/icons/focus.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import type { SVGProps } from "react"; - -export function FocusIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - - ); -} diff --git a/src/components/icons/follow.tsx b/src/components/icons/follow.tsx deleted file mode 100644 index 73e534d9..00000000 --- a/src/components/icons/follow.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function FollowIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/follows.tsx b/src/components/icons/follows.tsx deleted file mode 100644 index 6dc71c68..00000000 --- a/src/components/icons/follows.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function FollowsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/foryou.tsx b/src/components/icons/foryou.tsx deleted file mode 100644 index d583e200..00000000 --- a/src/components/icons/foryou.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ForyouIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/global.tsx b/src/components/icons/global.tsx deleted file mode 100644 index bd07e4cf..00000000 --- a/src/components/icons/global.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function GlobalIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/gossip.tsx b/src/components/icons/gossip.tsx deleted file mode 100644 index e9477294..00000000 --- a/src/components/icons/gossip.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function GossipIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - - - ); -} diff --git a/src/components/icons/groupFeeds.tsx b/src/components/icons/groupFeeds.tsx deleted file mode 100644 index d23cffbe..00000000 --- a/src/components/icons/groupFeeds.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { SVGProps } from "react"; - -export function GroupFeedsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/handArrowDown.tsx b/src/components/icons/handArrowDown.tsx deleted file mode 100644 index 7f56c80b..00000000 --- a/src/components/icons/handArrowDown.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import type { SVGProps } from "react"; - -export function HandArrowDownIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/hashtag.tsx b/src/components/icons/hashtag.tsx deleted file mode 100644 index 8cfe9159..00000000 --- a/src/components/icons/hashtag.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function HashtagIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/heading1.tsx b/src/components/icons/heading1.tsx deleted file mode 100644 index 0dcf7c43..00000000 --- a/src/components/icons/heading1.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function Heading1Icon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/heading2.tsx b/src/components/icons/heading2.tsx deleted file mode 100644 index d8c9dc26..00000000 --- a/src/components/icons/heading2.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function Heading2Icon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/heading3.tsx b/src/components/icons/heading3.tsx deleted file mode 100644 index 064c94f9..00000000 --- a/src/components/icons/heading3.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function Heading3Icon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/heartbeat.tsx b/src/components/icons/heartbeat.tsx deleted file mode 100644 index 3b637050..00000000 --- a/src/components/icons/heartbeat.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function HeartBeatIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/help.tsx b/src/components/icons/help.tsx deleted file mode 100644 index 827bb580..00000000 --- a/src/components/icons/help.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function HelpIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/hide.tsx b/src/components/icons/hide.tsx deleted file mode 100644 index 02955e40..00000000 --- a/src/components/icons/hide.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function HideIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/home.tsx b/src/components/icons/home.tsx deleted file mode 100644 index df6c07c3..00000000 --- a/src/components/icons/home.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function HomeIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/homeFilled.tsx b/src/components/icons/homeFilled.tsx deleted file mode 100644 index 1cc0e84a..00000000 --- a/src/components/icons/homeFilled.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export function HomeFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/horizontalDots.tsx b/src/components/icons/horizontalDots.tsx deleted file mode 100644 index d9b334e5..00000000 --- a/src/components/icons/horizontalDots.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function HorizontalDotsIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - - ); -} diff --git a/src/components/icons/image.tsx b/src/components/icons/image.tsx deleted file mode 100644 index ec8965fa..00000000 --- a/src/components/icons/image.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function ImageIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts deleted file mode 100644 index 00f50c5b..00000000 --- a/src/components/icons/index.ts +++ /dev/null @@ -1,128 +0,0 @@ -export * from "./addWidget"; -export * from "./arrowLeft"; -export * from "./arrowRight"; -export * from "./bell"; -export * from "./cancel"; -export * from "./checkCircle"; -export * from "./chevronDown"; -export * from "./chevronRight"; -export * from "./compose"; -export * from "./copy"; -export * from "./edit"; -export * from "./enter"; -export * from "./eyeOff"; -export * from "./eyeOn"; -export * from "./feed"; -export * from "./heartbeat"; -export * from "./hide"; -export * from "./image"; -export * from "./like"; -export * from "./lume"; -export * from "./media"; -export * from "./mute"; -export * from "./space"; -export * from "./spaceFilled"; -export * from "./navArrowDown"; -export * from "./plus"; -export * from "./plusCircle"; -export * from "./refresh"; -export * from "./reply"; -export * from "./replyMessage"; -export * from "./repost"; -export * from "./threads"; -export * from "./trash"; -export * from "./world"; -export * from "./zap"; -export * from "./trending"; -export * from "./empty"; -export * from "./cmd"; -export * from "./verticalDots"; -export * from "./signal"; -export * from "./unverified"; -export * from "./settings"; -export * from "./logout"; -export * from "./follow"; -export * from "./unfollow"; -export * from "./reaction"; -export * from "./thread"; -export * from "./strangers"; -export * from "./download"; -export * from "./horizontalDots"; -export * from "./arrowRightCircle"; -export * from "./hashtag"; -export * from "./file"; -export * from "./share"; -export * from "./expand"; -export * from "./focus"; -export * from "./chevronUp"; -export * from "./secure"; -export * from "./verified"; -export * from "./mention"; -export * from "./groupFeeds"; -export * from "./article"; -export * from "./follows"; -export * from "./alby"; -export * from "./stars"; -export * from "./nwc"; -export * from "./timeline"; -export * from "./dots"; -export * from "./handArrowDown"; -export * from "./relay"; -export * from "./explore"; -export * from "./explore2"; -export * from "./home"; -export * from "./chats"; -export * from "./community"; -export * from "./heading1"; -export * from "./heading2"; -export * from "./heading3"; -export * from "./bold"; -export * from "./italic"; -export * from "./user"; -export * from "./advancedSettings"; -export * from "./info"; -export * from "./light"; -export * from "./dark"; -export * from "./system"; -export * from "./announcement"; -export * from "./depot"; -export * from "./search"; -export * from "./run"; -export * from "./gossip"; -export * from "./userAdd"; -export * from "./userRemove"; -export * from "./pin"; -export * from "./homeFilled"; -export * from "./relayFilled"; -export * from "./depotFilled"; -export * from "./nwcFilled"; -export * from "./moveLeft"; -export * from "./moveRight"; -export * from "./help"; -export * from "./plusSquare"; -export * from "./column"; -export * from "./addMedia"; -export * from "./check"; -export * from "./popperFilled"; -export * from "./composeFilled"; -export * from "./settingsFilled"; -export * from "./bellFilled"; -export * from "./foryou"; -export * from "./editInterest"; -export * from "./newColumn"; -export * from "./searchFilled"; -export * from "./arrowUp"; -export * from "./arrowUpSquare"; -export * from "./arrowDown"; -export * from "./link"; -export * from "./local"; -export * from "./global"; -export * from "./infoCircle"; -export * from "./cancelCircle"; -export * from "./laurel"; -export * from "./quote"; -export * from "./key"; -export * from "./remote"; -export * from "./nsfw"; -export * from "./visit"; -export * from "./pow"; diff --git a/src/components/icons/info.tsx b/src/components/icons/info.tsx deleted file mode 100644 index efff1b5f..00000000 --- a/src/components/icons/info.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import type { SVGProps } from "react"; - -export function InfoIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/infoCircle.tsx b/src/components/icons/infoCircle.tsx deleted file mode 100644 index 671168f4..00000000 --- a/src/components/icons/infoCircle.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function InfoCircleIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/italic.tsx b/src/components/icons/italic.tsx deleted file mode 100644 index dd6f46bc..00000000 --- a/src/components/icons/italic.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ItalicIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/key.tsx b/src/components/icons/key.tsx deleted file mode 100644 index 7e0fb010..00000000 --- a/src/components/icons/key.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function KeyIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/laurel.tsx b/src/components/icons/laurel.tsx deleted file mode 100644 index 0d9bff68..00000000 --- a/src/components/icons/laurel.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function LaurelIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/light.tsx b/src/components/icons/light.tsx deleted file mode 100644 index 0cafe5e8..00000000 --- a/src/components/icons/light.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function LightIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/like.tsx b/src/components/icons/like.tsx deleted file mode 100644 index a2fd9286..00000000 --- a/src/components/icons/like.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function LikeIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/link.tsx b/src/components/icons/link.tsx deleted file mode 100644 index 34cdf6cd..00000000 --- a/src/components/icons/link.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function LinkIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/local.tsx b/src/components/icons/local.tsx deleted file mode 100644 index 5339cfa0..00000000 --- a/src/components/icons/local.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export function LocalIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - - ); -} diff --git a/src/components/icons/logout.tsx b/src/components/icons/logout.tsx deleted file mode 100644 index 0328a338..00000000 --- a/src/components/icons/logout.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function LogoutIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/lume.tsx b/src/components/icons/lume.tsx deleted file mode 100644 index d37bce44..00000000 --- a/src/components/icons/lume.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export function LumeIcon({ className }: { className: string }) { - return ( - - - - ); -} diff --git a/src/components/icons/media.tsx b/src/components/icons/media.tsx deleted file mode 100644 index 6ac8f93a..00000000 --- a/src/components/icons/media.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { SVGProps } from "react"; - -export function MediaIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/mention.tsx b/src/components/icons/mention.tsx deleted file mode 100644 index 22e64730..00000000 --- a/src/components/icons/mention.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function MentionIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/moveLeft.tsx b/src/components/icons/moveLeft.tsx deleted file mode 100644 index 2068df41..00000000 --- a/src/components/icons/moveLeft.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function MoveLeftIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/moveRight.tsx b/src/components/icons/moveRight.tsx deleted file mode 100644 index 5d82474f..00000000 --- a/src/components/icons/moveRight.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function MoveRightIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/mute.tsx b/src/components/icons/mute.tsx deleted file mode 100644 index fb9b12eb..00000000 --- a/src/components/icons/mute.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { SVGProps } from "react"; - -export function MuteIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/navArrowDown.tsx b/src/components/icons/navArrowDown.tsx deleted file mode 100644 index 12ab18a7..00000000 --- a/src/components/icons/navArrowDown.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function NavArrowDownIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/newColumn.tsx b/src/components/icons/newColumn.tsx deleted file mode 100644 index f14b2f04..00000000 --- a/src/components/icons/newColumn.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function NewColumnIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/nsfw.tsx b/src/components/icons/nsfw.tsx deleted file mode 100644 index 33851688..00000000 --- a/src/components/icons/nsfw.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function NsfwIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/nwc.tsx b/src/components/icons/nwc.tsx deleted file mode 100644 index 8f6247fe..00000000 --- a/src/components/icons/nwc.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export function NwcIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/nwcFilled.tsx b/src/components/icons/nwcFilled.tsx deleted file mode 100644 index 7d28eb6a..00000000 --- a/src/components/icons/nwcFilled.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function NwcFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/pin.tsx b/src/components/icons/pin.tsx deleted file mode 100644 index 3e63e677..00000000 --- a/src/components/icons/pin.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function PinIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/plus.tsx b/src/components/icons/plus.tsx deleted file mode 100644 index be837ef6..00000000 --- a/src/components/icons/plus.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function PlusIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/plusCircle.tsx b/src/components/icons/plusCircle.tsx deleted file mode 100644 index 79c8739e..00000000 --- a/src/components/icons/plusCircle.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function PlusCircleIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/plusSquare.tsx b/src/components/icons/plusSquare.tsx deleted file mode 100644 index 85ee88fe..00000000 --- a/src/components/icons/plusSquare.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export function PlusSquareIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/popperFilled.tsx b/src/components/icons/popperFilled.tsx deleted file mode 100644 index bf749bc4..00000000 --- a/src/components/icons/popperFilled.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function PopperFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/pow.tsx b/src/components/icons/pow.tsx deleted file mode 100644 index 85f53293..00000000 --- a/src/components/icons/pow.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function PowIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - - ); -} diff --git a/src/components/icons/quote.tsx b/src/components/icons/quote.tsx deleted file mode 100644 index c67cce4e..00000000 --- a/src/components/icons/quote.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function QuoteIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/reaction.tsx b/src/components/icons/reaction.tsx deleted file mode 100644 index b281a45d..00000000 --- a/src/components/icons/reaction.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function ReactionIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/refresh.tsx b/src/components/icons/refresh.tsx deleted file mode 100644 index 0b4ee885..00000000 --- a/src/components/icons/refresh.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function RefreshIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - - ); -} diff --git a/src/components/icons/relay.tsx b/src/components/icons/relay.tsx deleted file mode 100644 index 54ab8827..00000000 --- a/src/components/icons/relay.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function RelayIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/relayFilled.tsx b/src/components/icons/relayFilled.tsx deleted file mode 100644 index e2e8fe59..00000000 --- a/src/components/icons/relayFilled.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function RelayFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/remote.tsx b/src/components/icons/remote.tsx deleted file mode 100644 index 59c055be..00000000 --- a/src/components/icons/remote.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function RemoteIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/reply.tsx b/src/components/icons/reply.tsx deleted file mode 100644 index c92f107f..00000000 --- a/src/components/icons/reply.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function ReplyIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/replyMessage.tsx b/src/components/icons/replyMessage.tsx deleted file mode 100644 index 67b18d6f..00000000 --- a/src/components/icons/replyMessage.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { SVGProps } from "react"; - -export function ReplyMessageIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/repost.tsx b/src/components/icons/repost.tsx deleted file mode 100644 index b05027aa..00000000 --- a/src/components/icons/repost.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function RepostIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/run.tsx b/src/components/icons/run.tsx deleted file mode 100644 index f9e08985..00000000 --- a/src/components/icons/run.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function RunIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/search.tsx b/src/components/icons/search.tsx deleted file mode 100644 index 04bdf187..00000000 --- a/src/components/icons/search.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function SearchIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/searchFilled.tsx b/src/components/icons/searchFilled.tsx deleted file mode 100644 index 67904bee..00000000 --- a/src/components/icons/searchFilled.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function SearchFilledIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/secure.tsx b/src/components/icons/secure.tsx deleted file mode 100644 index 626dc4b9..00000000 --- a/src/components/icons/secure.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function SecureIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/settings.tsx b/src/components/icons/settings.tsx deleted file mode 100644 index e8d1622c..00000000 --- a/src/components/icons/settings.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { SVGProps } from "react"; - -export function SettingsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/settingsFilled.tsx b/src/components/icons/settingsFilled.tsx deleted file mode 100644 index 8368b204..00000000 --- a/src/components/icons/settingsFilled.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function SettingsFilledIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/share.tsx b/src/components/icons/share.tsx deleted file mode 100644 index ae7273d4..00000000 --- a/src/components/icons/share.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function ShareIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/signal.tsx b/src/components/icons/signal.tsx deleted file mode 100644 index 28ea6f79..00000000 --- a/src/components/icons/signal.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function SignalIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/space.tsx b/src/components/icons/space.tsx deleted file mode 100644 index 25b085e3..00000000 --- a/src/components/icons/space.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { SVGProps } from "react"; - -export function SpaceIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/spaceFilled.tsx b/src/components/icons/spaceFilled.tsx deleted file mode 100644 index 12152c68..00000000 --- a/src/components/icons/spaceFilled.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { SVGProps } from "react"; - -export function SpaceFilledIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/stars.tsx b/src/components/icons/stars.tsx deleted file mode 100644 index 843d2306..00000000 --- a/src/components/icons/stars.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function StarsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/strangers.tsx b/src/components/icons/strangers.tsx deleted file mode 100644 index 2ff36216..00000000 --- a/src/components/icons/strangers.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function StrangersIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/system.tsx b/src/components/icons/system.tsx deleted file mode 100644 index bb4d0e13..00000000 --- a/src/components/icons/system.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function SystemModeIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/thread.tsx b/src/components/icons/thread.tsx deleted file mode 100644 index 15173933..00000000 --- a/src/components/icons/thread.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export function ThreadIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/threads.tsx b/src/components/icons/threads.tsx deleted file mode 100644 index 31825266..00000000 --- a/src/components/icons/threads.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from "react"; - -export function ThreadsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/timeline.tsx b/src/components/icons/timeline.tsx deleted file mode 100644 index 243849a5..00000000 --- a/src/components/icons/timeline.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function TimelineIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/trash.tsx b/src/components/icons/trash.tsx deleted file mode 100644 index 722b7ece..00000000 --- a/src/components/icons/trash.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export function TrashIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/trending.tsx b/src/components/icons/trending.tsx deleted file mode 100644 index b7ca5ede..00000000 --- a/src/components/icons/trending.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function TrendingIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/unfollow.tsx b/src/components/icons/unfollow.tsx deleted file mode 100644 index a1a73682..00000000 --- a/src/components/icons/unfollow.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function UnfollowIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/unverified.tsx b/src/components/icons/unverified.tsx deleted file mode 100644 index 69fef612..00000000 --- a/src/components/icons/unverified.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { SVGProps } from "react"; - -export function UnverifiedIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/user.tsx b/src/components/icons/user.tsx deleted file mode 100644 index 47b185ba..00000000 --- a/src/components/icons/user.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function UserIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/userAdd.tsx b/src/components/icons/userAdd.tsx deleted file mode 100644 index 4a7fca0c..00000000 --- a/src/components/icons/userAdd.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function UserAddIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/userRemove.tsx b/src/components/icons/userRemove.tsx deleted file mode 100644 index 7b2c2e98..00000000 --- a/src/components/icons/userRemove.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export function UserRemoveIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/icons/verified.tsx b/src/components/icons/verified.tsx deleted file mode 100644 index 898376e4..00000000 --- a/src/components/icons/verified.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { SVGProps } from "react"; - -export function VerifiedIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/verticalDots.tsx b/src/components/icons/verticalDots.tsx deleted file mode 100644 index 761b768a..00000000 --- a/src/components/icons/verticalDots.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { SVGProps } from "react"; - -export function VerticalDotsIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/visit.tsx b/src/components/icons/visit.tsx deleted file mode 100644 index d43d11e5..00000000 --- a/src/components/icons/visit.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { SVGProps } from "react"; - -export function VisitIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - - ); -} diff --git a/src/components/icons/world.tsx b/src/components/icons/world.tsx deleted file mode 100644 index 70c560d3..00000000 --- a/src/components/icons/world.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { SVGProps } from "react"; - -export function WorldIcon( - props: JSX.IntrinsicAttributes & SVGProps, -) { - return ( - - - - ); -} diff --git a/src/components/icons/zap.tsx b/src/components/icons/zap.tsx deleted file mode 100644 index 50de1204..00000000 --- a/src/components/icons/zap.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function ZapIcon(props: JSX.IntrinsicElements["svg"]) { - return ( - - - - ); -} diff --git a/src/components/index.ts b/src/components/index.ts index 7eb84fe9..57d3586e 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,16 +1,15 @@ -export * from "./container"; export * from "./frame"; export * from "./back"; -export * from "./box"; export * from "./spinner"; -export * from "./quote"; -export * from "./text"; -export * from "./toolbar"; +export * from "./column"; + +// Newsfeed export * from "./repost"; export * from "./conversation"; -export * from "./column"; -export * from "./avatarUploader"; +export * from "./quote"; +export * from "./text"; +export * from "./reply"; +// Global components export * from "./note"; export * from "./user"; -export * from "./icons"; diff --git a/src/components/note/buttons/open.tsx b/src/components/note/buttons/open.tsx index 8fd5fbba..3aeebcc1 100644 --- a/src/components/note/buttons/open.tsx +++ b/src/components/note/buttons/open.tsx @@ -1,5 +1,5 @@ -import { VisitIcon } from "@/components"; import { LumeWindow } from "@/system"; +import { FrameCorners } from "@phosphor-icons/react"; import * as Tooltip from "@radix-ui/react-tooltip"; import { useNoteContext } from "../provider"; @@ -15,7 +15,7 @@ export function NoteOpenThread() { onClick={() => LumeWindow.openEvent(event)} className="group inline-flex h-7 w-14 bg-neutral-100 dark:bg-white/10 rounded-full items-center justify-center text-sm font-medium text-neutral-800 dark:text-neutral-200 hover:text-blue-500 hover:bg-neutral-200 dark:hover:bg-white/20" > - + diff --git a/src/components/note/buttons/reply.tsx b/src/components/note/buttons/reply.tsx index 7ff4d8b2..e6d7f169 100644 --- a/src/components/note/buttons/reply.tsx +++ b/src/components/note/buttons/reply.tsx @@ -1,6 +1,6 @@ import { cn } from "@/commons"; -import { ReplyIcon } from "@/components"; import { LumeWindow } from "@/system"; +import { ShareFat } from "@phosphor-icons/react"; import * as Tooltip from "@radix-ui/react-tooltip"; import { useNoteContext } from "../provider"; @@ -21,7 +21,7 @@ export function NoteReply({ large = false }: { large?: boolean }) { : "size-7", )} > - + {large ? "Reply" : null} diff --git a/src/components/note/buttons/repost.tsx b/src/components/note/buttons/repost.tsx index 78948e70..a93ce42b 100644 --- a/src/components/note/buttons/repost.tsx +++ b/src/components/note/buttons/repost.tsx @@ -1,16 +1,16 @@ -import { cn } from "@/commons"; +import { appSettings, cn } from "@/commons"; import { Spinner } from "@/components"; -import { RepostIcon } from "@/components"; import { LumeWindow } from "@/system"; -import { useRouteContext } from "@tanstack/react-router"; +import { Repeat } from "@phosphor-icons/react"; +import { useStore } from "@tanstack/react-store"; import { Menu, MenuItem } from "@tauri-apps/api/menu"; import { message } from "@tauri-apps/plugin-dialog"; import { useCallback, useState } from "react"; import { useNoteContext } from "../provider"; export function NoteRepost({ large = false }: { large?: boolean }) { + const visible = useStore(appSettings, (state) => state.display_repost_button); const event = useNoteContext(); - const { settings } = useRouteContext({ strict: false }); const [loading, setLoading] = useState(false); const [isRepost, setIsRepost] = useState(false); @@ -57,7 +57,7 @@ export function NoteRepost({ large = false }: { large?: boolean }) { await menu.popup().catch((e) => console.error(e)); }, []); - if (!settings.display_repost_button) return null; + if (!visible) return null; return ( diff --git a/src/components/note/buttons/zap.tsx b/src/components/note/buttons/zap.tsx index 15af4bb9..f6016c5c 100644 --- a/src/components/note/buttons/zap.tsx +++ b/src/components/note/buttons/zap.tsx @@ -1,14 +1,14 @@ -import { cn } from "@/commons"; -import { ZapIcon } from "@/components"; +import { appSettings, cn } from "@/commons"; import { LumeWindow } from "@/system"; -import { useRouteContext } from "@tanstack/react-router"; +import { Lightning } from "@phosphor-icons/react"; +import { useStore } from "@tanstack/react-store"; import { useNoteContext } from "../provider"; export function NoteZap({ large = false }: { large?: boolean }) { + const visible = useStore(appSettings, (state) => state.display_zap_button); const event = useNoteContext(); - const { settings } = useRouteContext({ strict: false }); - if (!settings.display_zap_button) return null; + if (!visible) return null; return ( ); diff --git a/src/components/note/child.tsx b/src/components/note/child.tsx index 9bb2ed5c..5fbf50f7 100644 --- a/src/components/note/child.tsx +++ b/src/components/note/child.tsx @@ -1,7 +1,7 @@ import { cn } from "@/commons"; -import { InfoIcon } from "@/components"; import { useEvent } from "@/system"; import type { EventTag } from "@/types"; +import { Info } from "@phosphor-icons/react"; import { Note } from "."; export function NoteChild({ @@ -11,7 +11,7 @@ export function NoteChild({ event: EventTag; isRoot?: boolean; }) { - const { isLoading, isError, data } = useEvent(event.id, event.relayHint); + const { isLoading, isError, data } = useEvent(event.id); if (isLoading) { return ( @@ -26,7 +26,7 @@ export function NoteChild({ return (
- +

Event not found with your current relay set diff --git a/src/components/note/content.tsx b/src/components/note/content.tsx index 78143d2b..784b5f8f 100644 --- a/src/components/note/content.tsx +++ b/src/components/note/content.tsx @@ -1,7 +1,7 @@ -import { cn } from "@/commons"; -import { useRouteContext } from "@tanstack/react-router"; +import { appSettings, cn } from "@/commons"; +import { useStore } from "@tanstack/react-store"; import { nanoid } from "nanoid"; -import { type ReactNode, useMemo, useState } from "react"; +import { type ReactNode, memo, useMemo, useState } from "react"; import reactStringReplace from "react-string-replace"; import { Hashtag } from "./mentions/hashtag"; import { MentionNote } from "./mentions/note"; @@ -21,9 +21,8 @@ export function NoteContent({ clean?: boolean; className?: string; }) { - const { settings } = useRouteContext({ strict: false }); const event = useNoteContext(); - + const visible = useStore(appSettings, (state) => state.display_media); const warning = useMemo(() => event.warning, [event]); const content = useMemo(() => { try { @@ -31,9 +30,7 @@ export function NoteContent({ const { content, hashtags, events, mentions } = event.meta; // Define rich content - let richContent: ReactNode[] | string = settings.display_media - ? content - : event.content; + let richContent: ReactNode[] | string = visible ? content : event.content; for (const hashtag of hashtags) { const regex = new RegExp(`(|^)${hashtag}\\b`, "g"); @@ -92,41 +89,19 @@ export function NoteContent({ } }, [event.content]); - const [blurred, setBlurred] = useState(() => warning?.length > 0); - return (

- {blurred ? ( -
-
-

- The content is hidden because the author -
- marked it with a warning for a reason: -

-

{warning}

- -
-
- ) : null} +
500 - ? "max-h-[250px] gradient-mask-b-0" - : "", + event.content.length > 500 ? "max-h-[250px] gradient-mask-b-0" : "", className, )} > {content}
- {settings.display_media ? ( + {visible ? ( <> {event.meta?.images.length ? ( @@ -139,3 +114,31 @@ export function NoteContent({
); } + +const ContentWarning = memo(function ContentWarning({ + warning, +}: { warning: string }) { + const [blurred, setBlurred] = useState(() => warning?.length > 0); + + if (!blurred) return null; + + return ( +
+
+

+ The content is hidden because the author +
+ marked it with a warning for a reason: +

+

{warning}

+ +
+
+ ); +}); diff --git a/src/components/note/mentions/hashtag.tsx b/src/components/note/mentions/hashtag.tsx index b9062560..b2080a72 100644 --- a/src/components/note/mentions/hashtag.tsx +++ b/src/components/note/mentions/hashtag.tsx @@ -1,10 +1,13 @@ +import { LumeWindow } from "@/system"; + export function Hashtag({ tag }: { tag: string }) { return ( - - # - - {tag.replace("#", "")} - - + ); } diff --git a/src/components/note/mentions/note.tsx b/src/components/note/mentions/note.tsx index b71cf44d..c0292607 100644 --- a/src/components/note/mentions/note.tsx +++ b/src/components/note/mentions/note.tsx @@ -1,76 +1,65 @@ -import { Spinner } from "@/components"; -import { LinkIcon } from "@/components"; +import { replyTime } from "@/commons"; +import { Note, Spinner } from "@/components"; import { User } from "@/components/user"; import { LumeWindow, useEvent } from "@/system"; +import { memo } from "react"; -export function MentionNote({ +export const MentionNote = memo(function MentionNote({ eventId, - openable = true, }: { eventId: string; - openable?: boolean; }) { - const { isLoading, isError, data } = useEvent(eventId); - - if (isLoading) { - return ( -
-
- -
-
- ); - } - - if (isError || !data) { - return ( -
-
-

- Event not found with your current relay set -

-
-
- ); - } + const { isLoading, isError, error, data: event } = useEvent(eventId); return ( -
-
- - - -
- - · - -
-
-
-
- {data.content} -
- {openable ? ( -
- -
+
+
+ {isLoading ? ( + + ) : isError || !event ? ( +

+ {error.message || + "Quoted note is not found with your current relay set"} +

) : ( -
+ + +
+
+ + + +
+ {event.content.length > 120 + ? `${event.content.substring(0, 120)}...` + : event.content} +
+
+
+ + {replyTime(event.created_at)} + +
+ + + + +
+
+
+
+
)}
); -} +}); diff --git a/src/components/note/mentions/user.tsx b/src/components/note/mentions/user.tsx index 2fefda6f..54326dd1 100644 --- a/src/components/note/mentions/user.tsx +++ b/src/components/note/mentions/user.tsx @@ -1,7 +1,10 @@ import { displayNpub } from "@/commons"; import { LumeWindow, useProfile } from "@/system"; +import { memo } from "react"; -export function MentionUser({ pubkey }: { pubkey: string }) { +export const MentionUser = memo(function MentionUser({ + pubkey, +}: { pubkey: string }) { const { isLoading, isError, profile } = useProfile(pubkey); return ( @@ -14,7 +17,7 @@ export function MentionUser({ pubkey }: { pubkey: string }) { ? "@anon" : isError ? displayNpub(pubkey, 16) - : `@${profile?.name || profile?.display_name || "anon"}`} + : `@${profile?.name || profile?.display_name || displayNpub(pubkey, 16)}`} ); -} +}); diff --git a/src/components/note/menu.tsx b/src/components/note/menu.tsx index 9898b4c9..ea756756 100644 --- a/src/components/note/menu.tsx +++ b/src/components/note/menu.tsx @@ -1,4 +1,4 @@ -import { HorizontalDotsIcon } from "@/components"; +import { DotsThree } from "@phosphor-icons/react"; import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu"; import { writeText } from "@tauri-apps/plugin-clipboard-manager"; import { useCallback } from "react"; @@ -56,7 +56,7 @@ export function NoteMenu() { onClick={(e) => showContextMenu(e)} className="inline-flex items-center justify-center group size-7 text-neutral-600 dark:text-neutral-400" > - + ); } diff --git a/src/components/note/preview/image.tsx b/src/components/note/preview/image.tsx index 7d1d6791..265416a6 100644 --- a/src/components/note/preview/image.tsx +++ b/src/components/note/preview/image.tsx @@ -1,20 +1,23 @@ -import { useRouteContext } from "@tanstack/react-router"; -import { open } from "@tauri-apps/plugin-shell"; +import { appSettings } from "@/commons"; +import { useStore } from "@tanstack/react-store"; import { useMemo } from "react"; export function ImagePreview({ url }: { url: string }) { - const { settings } = useRouteContext({ strict: false }); + const [service, visible] = useStore(appSettings, (state) => [ + state.image_resize_service, + state.display_media, + ]); const imageUrl = useMemo(() => { - if (settings.image_resize_service.length) { - const newUrl = `${settings.image_resize_service}?url=${url}&ll&af&default=1&n=-1`; + if (service?.length) { + const newUrl = `${service}?url=${url}&ll&af&default=1&n=-1`; return newUrl; } else { return url; } - }, [settings.image_resize_service]); + }, [service]); - if (!settings.display_media) { + if (!visible) { return ( open(url)} - onKeyDown={() => open(url)} + className="max-h-[400px] w-full h-auto object-cover rounded-lg outline outline-1 -outline-offset-1 outline-black/15" onError={({ currentTarget }) => { currentTarget.onerror = null; currentTarget.src = "/404.jpg"; diff --git a/src/components/note/preview/images.tsx b/src/components/note/preview/images.tsx index e542c9ae..c22d5f05 100644 --- a/src/components/note/preview/images.tsx +++ b/src/components/note/preview/images.tsx @@ -1,14 +1,12 @@ -import { cn } from "@/commons"; +import { appSettings, cn } from "@/commons"; import { Spinner } from "@/components"; -import { ArrowLeftIcon, ArrowRightIcon } from "@/components"; -import { useRouteContext } from "@tanstack/react-router"; +import { ArrowLeft, ArrowRight } from "@phosphor-icons/react"; +import { useStore } from "@tanstack/react-store"; import { open } from "@tauri-apps/plugin-shell"; import useEmblaCarousel from "embla-carousel-react"; import { useCallback, useEffect, useMemo, useState } from "react"; export function Images({ urls }: { urls: string[] }) { - const { settings } = useRouteContext({ strict: false }); - const [slidesInView, setSlidesInView] = useState([]); const [emblaRef, emblaApi] = useEmblaCarousel({ dragFree: true, @@ -16,19 +14,19 @@ export function Images({ urls }: { urls: string[] }) { watchSlides: false, }); + const service = useStore(appSettings, (state) => state.image_resize_service); + const imageUrls = useMemo(() => { - if (settings.image_resize_service.length) { + if (service?.length) { let newUrls: string[]; if (urls.length === 1) { newUrls = urls.map( - (url) => - `${settings.image_resize_service}?url=${url}&ll&af&default=1&n=-1`, + (url) => `${service}?url=${url}&ll&af&default=1&n=-1`, ); } else { newUrls = urls.map( - (url) => - `${settings.image_resize_service}?url=${url}&w=480&h=640&ll&af&default=1&n=-1`, + (url) => `${service}?url=${url}&w=480&h=640&ll&af&default=1&n=-1`, ); } @@ -36,7 +34,7 @@ export function Images({ urls }: { urls: string[] }) { } else { return urls; } - }, [settings.image_resize_service]); + }, [service]); const scrollPrev = useCallback(() => { if (emblaApi) emblaApi.scrollPrev(); @@ -80,7 +78,6 @@ export function Images({ urls }: { urls: string[] }) { {urls[0]} scrollPrev()} > - +
@@ -159,7 +156,6 @@ function LazyImage({ url, inView }: { url: string; inView: boolean }) { } data-src={url} alt={url} - loading="lazy" decoding="async" style={{ contentVisibility: "auto" }} className="object-cover w-full h-full rounded-lg outline outline-1 -outline-offset-1 outline-black/15" diff --git a/src/components/note/preview/video.tsx b/src/components/note/preview/video.tsx index 04d7db36..ff3fcf51 100644 --- a/src/components/note/preview/video.tsx +++ b/src/components/note/preview/video.tsx @@ -1,9 +1,10 @@ -import { useRouteContext } from "@tanstack/react-router"; +import { appSettings } from "@/commons"; +import { useStore } from "@tanstack/react-store"; export function VideoPreview({ url }: { url: string }) { - const { settings } = useRouteContext({ strict: false }); + const visible = useStore(appSettings, (state) => state.display_media); - if (settings.display_media) { + if (!visible) { return (
-
- - -
+
·
- + Quote
diff --git a/src/components/reply.tsx b/src/components/reply.tsx new file mode 100644 index 00000000..a152b02d --- /dev/null +++ b/src/components/reply.tsx @@ -0,0 +1,126 @@ +import { cn, replyTime } from "@/commons"; +import { Note } from "@/components/note"; +import type { LumeEvent } from "@/system"; +import { CaretDown } from "@phosphor-icons/react"; +import { Link, useSearch } from "@tanstack/react-router"; +import { memo } from "react"; +import { User } from "./user"; + +export const ReplyNote = memo(function ReplyNote({ + event, + className, +}: { + event: LumeEvent; + className?: string; +}) { + const search = useSearch({ strict: false }); + + return ( + + + + + + +
+
+ +
+ {event.content} +
+
+
+ + {replyTime(event.created_at)} + +
+ + + +
+
+ {event.replies?.length ? ( +
+
+ {event.replies.slice(0, 2).map((reply) => ( + + ))} + {event.replies.length > 2 ? ( + +
+
All {event.replies.length} replies
+ +
+ + ) : null} +
+
+ ) : null} +
+
+
+
+ ); +}); + +function ChildReply({ event }: { event: LumeEvent }) { + const search = useSearch({ strict: false }); + + return ( + + +
+
+ + + +
+ {event.content} +
+
+
+ + {replyTime(event.created_at)} + +
+ + + +
+
+ {event.replies?.length ? ( +
+
+ {event.replies.slice(0, 2).map((reply) => ( + + ))} + {event.replies.length > 2 ? ( + +
+
All {event.replies.length} replies
+ +
+ + ) : null} +
+
+ ) : null} +
+
+
+ ); +} diff --git a/src/components/toolbar.tsx b/src/components/toolbar.tsx deleted file mode 100644 index d403407c..00000000 --- a/src/components/toolbar.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { ReactNode } from "@tanstack/react-router"; -import { useLayoutEffect, useState } from "react"; -import { createPortal } from "react-dom"; - -export function Toolbar({ children }: { children: ReactNode }) { - const [domReady, setDomReady] = useState(false); - - useLayoutEffect(() => { - setDomReady(true); - }, []); - - return domReady - ? createPortal(children, document.getElementById("toolbar")) - : null; -} diff --git a/src/components/user/avatar.tsx b/src/components/user/avatar.tsx index 6e52bbc6..7e526658 100644 --- a/src/components/user/avatar.tsx +++ b/src/components/user/avatar.tsx @@ -1,20 +1,21 @@ -import { cn } from "@/commons"; +import { appSettings, cn } from "@/commons"; import * as Avatar from "@radix-ui/react-avatar"; -import { useRouteContext } from "@tanstack/react-router"; +import { useStore } from "@tanstack/react-store"; import { minidenticon } from "minidenticons"; import { useMemo } from "react"; import { useUserContext } from "./provider"; export function UserAvatar({ className }: { className?: string }) { + const [service, visible] = useStore(appSettings, (state) => [ + state.image_resize_service, + state.display_avatar, + ]); + const user = useUserContext(); - const { settings } = useRouteContext({ strict: false }); const picture = useMemo(() => { - if ( - settings?.image_resize_service?.length && - user.profile?.picture?.length - ) { - const url = `${settings.image_resize_service}?url=${user.profile?.picture}&w=100&h=100&default=1&n=-1`; + if (service?.length && user.profile?.picture?.length) { + const url = `${service}?url=${user.profile?.picture}&w=100&h=100&default=1&n=-1`; return url; } else { return user.profile?.picture; @@ -29,27 +30,6 @@ export function UserAvatar({ className }: { className?: string }) { [user.pubkey], ); - if (settings && !settings.display_avatar) { - return ( - - - {user.pubkey} - - - ); - } - return ( - + {visible ? ( + + ) : null} ); } diff --git a/src/components/user/followButton.tsx b/src/components/user/followButton.tsx index 93f91367..fb453884 100644 --- a/src/components/user/followButton.tsx +++ b/src/components/user/followButton.tsx @@ -1,7 +1,9 @@ +import { commands } from "@/commands.gen"; import { cn } from "@/commons"; import { Spinner } from "@/components"; import { NostrAccount } from "@/system"; -import { useEffect, useState } from "react"; +import { message } from "@tauri-apps/plugin-dialog"; +import { useEffect, useState, useTransition } from "react"; import { useUserContext } from "./provider"; export function UserFollowButton({ @@ -13,18 +15,20 @@ export function UserFollowButton({ }) { const user = useUserContext(); - const [loading, setLoading] = useState(false); const [followed, setFollowed] = useState(false); + const [isPending, startTransition] = useTransition(); - const toggleFollow = async () => { - setLoading(true); + const toggleFollow = () => { + startTransition(async () => { + const res = await commands.toggleContact(user.pubkey, null); - const toggle = await NostrAccount.toggleContact(user.pubkey); - - if (toggle) { - setFollowed((prev) => !prev); - setLoading(false); - } + if (res.status === "ok") { + setFollowed((prev) => !prev); + } else { + await message(res.error, { kind: "error" }); + return; + } + }); }; useEffect(() => { @@ -42,11 +46,11 @@ export function UserFollowButton({ return ( -
-
-
- -
-
- - -
-
-
- -
-
- ); -} - -const Accounts = memo(function Accounts() { - const { otherAccounts } = Route.useRouteContext(); - const { account } = Route.useParams(); - - const navigate = Route.useNavigate(); - - const showContextMenu = useCallback( - async (e: React.MouseEvent) => { - e.preventDefault(); - - const menuItems = await Promise.all([ - MenuItem.new({ - text: "New Post", - action: () => LumeWindow.openEditor(), - }), - PredefinedMenuItem.new({ item: "Separator" }), - MenuItem.new({ - text: "View Profile", - action: () => LumeWindow.openProfile(account), - }), - MenuItem.new({ - text: "Open Settings", - action: () => LumeWindow.openSettings(), - }), - ]); - - const menu = await Menu.new({ - items: menuItems, - }); - - await menu.popup().catch((e) => console.error(e)); - }, - [account], - ); - - const changeAccount = useCallback( - async (npub: string) => { - // Change current account and update signer - const select = await NostrAccount.loadAccount(npub); - - if (select) { - // Reset current columns - await getCurrentWindow().emit("columns", { type: "reset" }); - - // Redirect to new account - return navigate({ - to: "/$account/home", - params: { account: npub }, - resetScroll: true, - replace: true, - }); - } else { - await message("Something wrong.", { title: "Accounts", kind: "error" }); - } - }, - [otherAccounts], - ); - - return ( -
- {otherAccounts.map((npub) => ( - - ))} - -
- ); -}); - -const Search = memo(function Search() { - const [searchType, setSearchType] = useState<"notes" | "users">("notes"); - const [query, setQuery] = useState(""); - - const showContextMenu = useCallback(async (e: React.MouseEvent) => { - e.preventDefault(); - - const menuItems = await Promise.all([ - MenuItem.new({ - text: "Notes", - action: () => setSearchType("notes"), - }), - MenuItem.new({ - text: "Users", - action: () => setSearchType("users"), - }), - ]); - - const menu = await Menu.new({ - items: menuItems, - }); - - await menu.popup().catch((e) => console.error(e)); - }, []); - - return ( -
- - setQuery(e.target.value)} - onKeyDown={(event) => { - if (event.key === "Enter") { - LumeWindow.openSearch(searchType, query); - } - }} - className="h-full w-full px-3 text-sm rounded-full border-none ring-0 focus:ring-0 focus:outline-none bg-transparent placeholder:text-black/50 dark:placeholder:text-white/50" - /> - -
- ); -}); diff --git a/src/routes/$account.tsx b/src/routes/$account.tsx deleted file mode 100644 index 762425fd..00000000 --- a/src/routes/$account.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { NostrAccount, NostrQuery } from "@/system"; -import { createFileRoute } from "@tanstack/react-router"; - -export const Route = createFileRoute("/$account")({ - beforeLoad: async ({ params }) => { - const settings = await NostrQuery.getUserSettings(); - const accounts = await NostrAccount.getAccounts(); - const otherAccounts = accounts.filter( - (account) => account !== params.account, - ); - - return { otherAccounts, settings }; - }, -}); diff --git a/src/routes/$account/_app.lazy.tsx b/src/routes/$account/_app.lazy.tsx new file mode 100644 index 00000000..650a3aa7 --- /dev/null +++ b/src/routes/$account/_app.lazy.tsx @@ -0,0 +1,126 @@ +import { appSettings, cn } from "@/commons"; +import { User } from "@/components/user"; +import { LumeWindow } from "@/system"; +import { CaretDown, Feather, MagnifyingGlass } from "@phosphor-icons/react"; +import { Outlet, createLazyFileRoute } from "@tanstack/react-router"; +import { useStore } from "@tanstack/react-store"; +import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu"; +import { writeText } from "@tauri-apps/plugin-clipboard-manager"; +import { memo, useCallback } from "react"; + +export const Route = createLazyFileRoute("/$account/_app")({ + component: Screen, +}); + +function Screen() { + const context = Route.useRouteContext(); + const transparent = useStore(appSettings, (state) => state.transparent); + + return ( +
+
+
+ +
+ + +
+
+
+
+
+ +
+
+ ); +} + +const Account = memo(function Account() { + const params = Route.useParams(); + const navigate = Route.useNavigate(); + + const showContextMenu = useCallback( + async (e: React.MouseEvent) => { + e.preventDefault(); + + const menuItems = await Promise.all([ + MenuItem.new({ + text: "New Post", + action: () => LumeWindow.openEditor(), + }), + MenuItem.new({ + text: "Profile", + action: () => LumeWindow.openProfile(params.account), + }), + MenuItem.new({ + text: "Settings", + action: () => LumeWindow.openSettings(params.account), + }), + PredefinedMenuItem.new({ item: "Separator" }), + MenuItem.new({ + text: "Copy Public Key", + action: async () => await writeText(params.account), + }), + MenuItem.new({ + text: "Logout", + action: () => navigate({ to: "/" }), + }), + ]); + + const menu = await Menu.new({ + items: menuItems, + }); + + await menu.popup().catch((e) => console.error(e)); + }, + [params.account], + ); + + return ( + + ); +}); diff --git a/src/routes/$account/_app.tsx b/src/routes/$account/_app.tsx new file mode 100644 index 00000000..8ae1fa1d --- /dev/null +++ b/src/routes/$account/_app.tsx @@ -0,0 +1,15 @@ +import type { LumeColumn } from "@/types"; +import { createFileRoute } from "@tanstack/react-router"; +import { resolveResource } from "@tauri-apps/api/path"; +import { readTextFile } from "@tauri-apps/plugin-fs"; + +export const Route = createFileRoute("/$account/_app")({ + beforeLoad: async () => { + const systemPath = "resources/columns.json"; + const resourcePath = await resolveResource(systemPath); + const resourceFile = await readTextFile(resourcePath); + const systemColumns: LumeColumn[] = JSON.parse(resourceFile); + + return { systemColumns }; + }, +}); diff --git a/src/routes/$account/home.lazy.tsx b/src/routes/$account/_app/home.lazy.tsx similarity index 64% rename from src/routes/$account/home.lazy.tsx rename to src/routes/$account/_app/home.lazy.tsx index 3df35ea8..aec03e3b 100644 --- a/src/routes/$account/home.lazy.tsx +++ b/src/routes/$account/_app/home.lazy.tsx @@ -1,22 +1,29 @@ -import { ArrowLeftIcon, ArrowRightIcon, PlusIcon } from "@/components"; +import { Spinner } from "@/components"; import { Column } from "@/components/column"; -import { Toolbar } from "@/components/toolbar"; -import { NostrQuery } from "@/system"; +import { LumeWindow, NostrQuery } from "@/system"; import type { ColumnEvent, LumeColumn } from "@/types"; +import { ArrowLeft, ArrowRight, Plus, StackPlus } from "@phosphor-icons/react"; import { createLazyFileRoute } from "@tanstack/react-router"; import { listen } from "@tauri-apps/api/event"; +import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu"; import { getCurrentWindow } from "@tauri-apps/api/window"; import useEmblaCarousel from "embla-carousel-react"; import { nanoid } from "nanoid"; -import { useCallback, useEffect, useState } from "react"; +import { + type ReactNode, + useCallback, + useEffect, + useLayoutEffect, + useState, +} from "react"; +import { createPortal } from "react-dom"; import { useDebouncedCallback } from "use-debounce"; -export const Route = createLazyFileRoute("/$account/home")({ +export const Route = createLazyFileRoute("/$account/_app/home")({ component: Screen, }); function Screen() { - const { account } = Route.useParams(); const initialColumnList = Route.useLoaderData(); const [columns, setColumns] = useState([]); @@ -26,11 +33,11 @@ function Screen() { }); const scrollPrev = useCallback(() => { - if (emblaApi) emblaApi.scrollPrev(); + if (emblaApi) emblaApi.scrollPrev(true); }, [emblaApi]); const scrollNext = useCallback(() => { - if (emblaApi) emblaApi.scrollNext(); + if (emblaApi) emblaApi.scrollNext(true); }, [emblaApi]); const emitScrollEvent = useCallback(() => { @@ -41,17 +48,6 @@ function Screen() { getCurrentWindow().emit("child_webview", { resize: true, direction: "x" }); }, []); - const openLumeStore = useCallback(async () => { - await getCurrentWindow().emit("columns", { - type: "add", - column: { - label: "store", - name: "Column Gallery", - content: "/store", - }, - }); - }, []); - const add = useDebouncedCallback((column: LumeColumn) => { column.label = `${column.label}-${nanoid()}`; // update col label setColumns((prev) => [column, ...prev]); @@ -124,7 +120,7 @@ function Screen() { }, [emblaApi, emitScrollEvent, emitResizeEvent]); useEffect(() => { - if (columns?.length) { + if (columns) { NostrQuery.setColumns(columns).then(() => console.log("saved")); } }, [columns]); @@ -163,21 +159,23 @@ function Screen() {
- {columns?.map((column) => ( - - ))} + {!columns ? ( +
+ +
+ ) : ( + columns.map((column) => ( + + )) + )}
-
+
@@ -185,21 +183,75 @@ function Screen() {
+
); } + +function ManageButton() { + const showContextMenu = useCallback(async (e: React.MouseEvent) => { + e.preventDefault(); + + const menuItems = await Promise.all([ + MenuItem.new({ + text: "Open Columns Gallery", + action: () => LumeWindow.openColumnsGallery(), + }), + PredefinedMenuItem.new({ item: "Separator" }), + MenuItem.new({ + text: "Add local feeds", + action: () => LumeWindow.openLocalFeeds(), + }), + MenuItem.new({ + text: "Add notification", + action: () => LumeWindow.openNotification(), + }), + ]); + + const menu = await Menu.new({ + items: menuItems, + }); + + await menu.popup().catch((e) => console.error(e)); + }, []); + + return ( + + ); +} + +function Toolbar({ children }: { children: ReactNode[] }) { + const [domReady, setDomReady] = useState(false); + + useLayoutEffect(() => { + setDomReady(true); + }, []); + + return domReady ? ( + // @ts-ignore, react bug ??? + createPortal(children, document.getElementById("toolbar")) + ) : ( + <> + ); +} diff --git a/src/routes/$account/_app/home.tsx b/src/routes/$account/_app/home.tsx new file mode 100644 index 00000000..cbdddc35 --- /dev/null +++ b/src/routes/$account/_app/home.tsx @@ -0,0 +1,18 @@ +import { commands } from "@/commands.gen"; +import type { LumeColumn } from "@/types"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_app/home")({ + loader: async ({ context }) => { + const key = "lume_v4:columns"; + const defaultColumns = context.systemColumns.filter((col) => col.default); + const query = await commands.getLumeStore(key); + + if (query.status === "ok") { + const columns: LumeColumn[] = JSON.parse(query.data); + return columns; + } else { + return defaultColumns; + } + }, +}); diff --git a/src/routes/$account/_settings.lazy.tsx b/src/routes/$account/_settings.lazy.tsx new file mode 100644 index 00000000..cb3d482b --- /dev/null +++ b/src/routes/$account/_settings.lazy.tsx @@ -0,0 +1,111 @@ +import { cn } from "@/commons"; +import { CurrencyBtc, GearSix, HardDrives, User } from "@phosphor-icons/react"; +import * as ScrollArea from "@radix-ui/react-scroll-area"; +import { Link } from "@tanstack/react-router"; +import { Outlet, createLazyFileRoute } from "@tanstack/react-router"; + +export const Route = createLazyFileRoute("/$account/_settings")({ + component: Screen, +}); + +function Screen() { + const { account } = Route.useParams(); + const { platform } = Route.useRouteContext(); + + return ( +
+
+ + {({ isActive }) => { + return ( +
+ +

General

+
+ ); + }} + + + {({ isActive }) => { + return ( +
+ +

Profile

+
+ ); + }} + + + {({ isActive }) => { + return ( +
+ +

Relay

+
+ ); + }} + + + {({ isActive }) => { + return ( +
+ +

Wallet

+
+ ); + }} + +
+ + + + + + + + + +
+ ); +} diff --git a/src/routes/settings/bitcoin-connect.tsx b/src/routes/$account/_settings/bitcoin-connect.lazy.tsx similarity index 70% rename from src/routes/settings/bitcoin-connect.tsx rename to src/routes/$account/_settings/bitcoin-connect.lazy.tsx index 139b9e6c..8ce98f57 100644 --- a/src/routes/settings/bitcoin-connect.tsx +++ b/src/routes/$account/_settings/bitcoin-connect.lazy.tsx @@ -1,18 +1,13 @@ -import { Button, init } from "@getalby/bitcoin-connect-react"; import { NostrAccount } from "@/system"; -import { createFileRoute } from "@tanstack/react-router"; +import { Button } from "@getalby/bitcoin-connect-react"; +import { createLazyFileRoute } from "@tanstack/react-router"; import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; -export const Route = createFileRoute("/settings/bitcoin-connect")({ - beforeLoad: () => { - init({ - appName: "Lume", - filters: ["nwc"], - showBalance: true, - }); +export const Route = createLazyFileRoute("/$account/_settings/bitcoin-connect")( + { + component: Screen, }, - component: Screen, -}); +); function Screen() { const setNwcUri = async (uri: string) => { diff --git a/src/routes/$account/_settings/bitcoin-connect.tsx b/src/routes/$account/_settings/bitcoin-connect.tsx new file mode 100644 index 00000000..1ddf1e1f --- /dev/null +++ b/src/routes/$account/_settings/bitcoin-connect.tsx @@ -0,0 +1,12 @@ +import { init } from "@getalby/bitcoin-connect-react"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_settings/bitcoin-connect")({ + beforeLoad: () => { + init({ + appName: "Lume", + filters: ["nwc"], + showBalance: true, + }); + }, +}); diff --git a/src/routes/$account/_settings/general.lazy.tsx b/src/routes/$account/_settings/general.lazy.tsx new file mode 100644 index 00000000..7879df0b --- /dev/null +++ b/src/routes/$account/_settings/general.lazy.tsx @@ -0,0 +1,179 @@ +import { commands } from "@/commands.gen"; +import { appSettings } from "@/commons"; +import { Spinner } from "@/components"; +import * as Switch from "@radix-ui/react-switch"; +import { createLazyFileRoute } from "@tanstack/react-router"; +import { useStore } from "@tanstack/react-store"; +import { invoke } from "@tauri-apps/api/core"; +import { message } from "@tauri-apps/plugin-dialog"; +import { useCallback, useEffect, useState, useTransition } from "react"; + +type Theme = "auto" | "light" | "dark"; + +export const Route = createLazyFileRoute("/$account/_settings/general")({ + component: Screen, +}); + +function Screen() { + const [theme, setTheme] = useState(null); + const [isPending, startTransition] = useTransition(); + + const changeTheme = useCallback(async (theme: string) => { + if (theme === "auto" || theme === "light" || theme === "dark") { + invoke("plugin:theme|set_theme", { + theme: theme, + }).then(() => setTheme(theme)); + } + }, []); + + const updateSettings = () => { + startTransition(async () => { + const newSettings = JSON.stringify(appSettings.state); + const res = await commands.setSettings(newSettings); + + if (res.status === "error") { + await message(res.error, { kind: "error" }); + } + + return; + }); + }; + + useEffect(() => { + invoke("plugin:theme|get_theme").then((data) => setTheme(data as Theme)); + }, []); + + return ( +
+
+
+

+ General +

+
+ + +
+
+
+

+ Appearance +

+
+
+
+

Appearance

+

+ Change app theme +

+
+
+ +
+
+ + + +
+
+
+

+ Privacy & Performance +

+
+ + + +
+
+
+
+ +
+
+ ); +} + +function Setting({ + label, + name, + description, +}: { label: string; name: string; description: string }) { + const state = useStore(appSettings, (state) => state[label]); + + const toggle = useCallback(() => { + appSettings.setState((state) => { + return { + ...state, + [label]: !state[label], + }; + }); + }, []); + + return ( +
+
+

{name}

+

+ {description} +

+
+
+ toggle()} + className="relative h-7 w-12 shrink-0 cursor-default rounded-full bg-black/10 outline-none data-[state=checked]:bg-blue-500 dark:bg-white/10" + > + + +
+
+ ); +} diff --git a/src/routes/$account/_settings/general.tsx b/src/routes/$account/_settings/general.tsx new file mode 100644 index 00000000..f9b1db31 --- /dev/null +++ b/src/routes/$account/_settings/general.tsx @@ -0,0 +1,17 @@ +import { commands } from "@/commands.gen"; +import { appSettings } from "@/commons"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_settings/general")({ + beforeLoad: async () => { + const res = await commands.getSettings(); + + if (res.status === "ok") { + appSettings.setState((state) => { + return { ...state, ...res.data }; + }); + } else { + throw new Error(res.error); + } + }, +}); diff --git a/src/routes/$account/_settings/profile.lazy.tsx b/src/routes/$account/_settings/profile.lazy.tsx new file mode 100644 index 00000000..9c5a20b3 --- /dev/null +++ b/src/routes/$account/_settings/profile.lazy.tsx @@ -0,0 +1,245 @@ +import { commands } from "@/commands.gen"; +import { cn } from "@/commons"; +import { Spinner } from "@/components"; +import { NostrAccount, NostrQuery } from "@/system"; +import type { Metadata } from "@/types"; +import { Plus } from "@phosphor-icons/react"; +import { createLazyFileRoute } from "@tanstack/react-router"; +import { writeText } from "@tauri-apps/plugin-clipboard-manager"; +import { message } from "@tauri-apps/plugin-dialog"; +import { + type Dispatch, + type ReactNode, + type SetStateAction, + useState, + useTransition, +} from "react"; +import { useForm } from "react-hook-form"; + +export const Route = createLazyFileRoute("/$account/_settings/profile")({ + component: Screen, +}); + +function Screen() { + const { profile } = Route.useRouteContext(); + const { register, handleSubmit } = useForm({ defaultValues: profile }); + + const [isPending, startTransition] = useTransition(); + const [picture, setPicture] = useState(""); + + const onSubmit = (data: Metadata) => { + startTransition(async () => { + try { + const newProfile: Metadata = { ...profile, ...data, picture }; + await NostrAccount.createProfile(newProfile); + } catch (e) { + await message(String(e), { title: "Profile", kind: "error" }); + return; + } + }); + }; + + return ( +
+
+
+ {profile.picture ? ( + avatar + ) : null} + + + +
+
+
+
{profile.display_name}
+
+ {profile.nip05} +
+
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ ); +} + +function PrivkeyButton() { + const { account } = Route.useParams(); + + const [isPending, startTransition] = useTransition(); + const [isCopy, setIsCopy] = useState(false); + + const copyPrivateKey = () => { + startTransition(async () => { + const res = await commands.getPrivateKey(account); + + if (res.status === "ok") { + await writeText(res.data); + setIsCopy(true); + } else { + await message(res.error, { kind: "error" }); + return; + } + }); + }; + + return ( + + ); +} + +function AvatarUploader({ + setPicture, + children, + className, +}: { + setPicture: Dispatch>; + children: ReactNode; + className?: string; +}) { + const [loading, setLoading] = useState(false); + + const uploadAvatar = async () => { + try { + setLoading(true); + const image = await NostrQuery.upload(); + setPicture(image); + } catch (e) { + setLoading(false); + await message(String(e), { title: "Lume", kind: "error" }); + } + }; + + return ( + + ); +} diff --git a/src/routes/$account/_settings/profile.tsx b/src/routes/$account/_settings/profile.tsx new file mode 100644 index 00000000..9d0582f0 --- /dev/null +++ b/src/routes/$account/_settings/profile.tsx @@ -0,0 +1,16 @@ +import { commands } from "@/commands.gen"; +import type { Metadata } from "@/types"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_settings/profile")({ + beforeLoad: async ({ params }) => { + const res = await commands.getProfile(params.account); + + if (res.status === "ok") { + const profile: Metadata = JSON.parse(res.data); + return { profile }; + } else { + throw new Error(res.error); + } + }, +}); diff --git a/src/routes/settings/relay.tsx b/src/routes/$account/_settings/relay.lazy.tsx similarity index 72% rename from src/routes/settings/relay.tsx rename to src/routes/$account/_settings/relay.lazy.tsx index d35e62a8..938d4e81 100644 --- a/src/routes/settings/relay.tsx +++ b/src/routes/$account/_settings/relay.lazy.tsx @@ -1,40 +1,45 @@ -import { CancelIcon, PlusIcon } from "@/components"; +import { commands } from "@/commands.gen"; import { NostrQuery } from "@/system"; -import { createFileRoute } from "@tanstack/react-router"; +import { Plus, X } from "@phosphor-icons/react"; +import { createLazyFileRoute } from "@tanstack/react-router"; import { message } from "@tauri-apps/plugin-dialog"; -import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; +import { useEffect, useState, useTransition } from "react"; -export const Route = createFileRoute("/settings/relay")({ - loader: async () => { - const relays = await NostrQuery.getRelays(); - return relays; - }, +export const Route = createLazyFileRoute("/$account/_settings/relay")({ component: Screen, }); function Screen() { - const relayList = Route.useLoaderData(); - const { register, reset, handleSubmit } = useForm(); + const { relayList } = Route.useRouteContext(); const [relays, setRelays] = useState([]); - const [isLoading, setIsLoading] = useState(false); + const [newRelay, setNewRelay] = useState(""); + const [isPending, startTransition] = useTransition(); - const onSubmit = async (data: { url: string }) => { - try { - setIsLoading(true); + const addNewRelay = () => { + startTransition(async () => { + try { + let url = newRelay; - const add = await NostrQuery.connectRelay(data.url); + if (!url.startsWith("wss://")) { + url = `wss://${url}`; + } - if (add) { - setRelays((prev) => [...prev, data.url]); - setIsLoading(false); - reset(); + const relay = new URL(url); + const res = await commands.connectRelay(relay.toString()); + + if (res.status === "ok") { + setRelays((prev) => [...prev, newRelay]); + setNewRelay(""); + } else { + await message(res.error, { title: "Relay", kind: "error" }); + return; + } + } catch { + await message("URL is not valid.", { kind: "error" }); + return; } - } catch (e) { - setIsLoading(false); - await message(String(e), { title: "Relay", kind: "error" }); - } + }); }; useEffect(() => { @@ -42,7 +47,7 @@ function Screen() { }, [relayList]); return ( -
+

@@ -67,34 +72,30 @@ function Screen() { onClick={() => NostrQuery.removeRelay(relay)} className="inline-flex items-center justify-center rounded-md size-7 hover:bg-black/10 dark:hover:bg-white/10" > - +

))}
-
+
setNewRelay(e.target.value)} name="url" placeholder="wss://..." spellCheck={false} className="flex-1 px-3 bg-transparent rounded-lg h-9 border-neutral-300 placeholder:text-neutral-500 focus:border-blue-500 focus:ring-0 dark:border-neutral-700 dark:placeholder:text-neutral-400" /> - +
diff --git a/src/routes/$account/_settings/relay.tsx b/src/routes/$account/_settings/relay.tsx new file mode 100644 index 00000000..89754b4d --- /dev/null +++ b/src/routes/$account/_settings/relay.tsx @@ -0,0 +1,15 @@ +import { commands } from "@/commands.gen"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_settings/relay")({ + beforeLoad: async () => { + const res = await commands.getRelays(); + + if (res.status === "ok") { + const relayList = res.data; + return { relayList }; + } else { + throw new Error(res.error); + } + }, +}); diff --git a/src/routes/settings/wallet.tsx b/src/routes/$account/_settings/wallet.lazy.tsx similarity index 72% rename from src/routes/settings/wallet.tsx rename to src/routes/$account/_settings/wallet.lazy.tsx index 7cabf3d2..64415d18 100644 --- a/src/routes/settings/wallet.tsx +++ b/src/routes/$account/_settings/wallet.lazy.tsx @@ -1,31 +1,23 @@ -import { getBitcoinDisplayValues } from "@/commons"; import { NostrAccount } from "@/system"; -import { createFileRoute, redirect } from "@tanstack/react-router"; +import { createLazyFileRoute, redirect } from "@tanstack/react-router"; -export const Route = createFileRoute("/settings/wallet")({ - beforeLoad: async () => { - const wallet = await NostrAccount.loadWallet(); - if (!wallet) { - throw redirect({ to: "/settings/bitcoin-connect" }); - } - const balance = getBitcoinDisplayValues(wallet); - return { balance }; - }, +export const Route = createLazyFileRoute("/$account/_settings/wallet")({ component: Screen, }); function Screen() { + const { account } = Route.useParams(); const { balance } = Route.useRouteContext(); const disconnect = async () => { window.localStorage.removeItem("bc:config"); await NostrAccount.removeWallet(); - return redirect({ to: "/settings/bitcoin-connect" }); + return redirect({ to: "/$account/bitcoin-connect", params: { account } }); }; return ( -
+
diff --git a/src/routes/$account/_settings/wallet.tsx b/src/routes/$account/_settings/wallet.tsx new file mode 100644 index 00000000..adf36b71 --- /dev/null +++ b/src/routes/$account/_settings/wallet.tsx @@ -0,0 +1,21 @@ +import { commands } from "@/commands.gen"; +import { getBitcoinDisplayValues } from "@/commons"; +import { createFileRoute, redirect } from "@tanstack/react-router"; + +export const Route = createFileRoute("/$account/_settings/wallet")({ + beforeLoad: async ({ params }) => { + const query = await commands.loadWallet(); + + if (query.status === "ok") { + const wallet = Number.parseInt(query.data); + const balance = getBitcoinDisplayValues(wallet); + + return { balance }; + } else { + throw redirect({ + to: "/$account/bitcoin-connect", + params: { account: params.account }, + }); + } + }, +}); diff --git a/src/routes/$account/backup.tsx b/src/routes/$account/backup.tsx index 0fef53c7..641c793d 100644 --- a/src/routes/$account/backup.tsx +++ b/src/routes/$account/backup.tsx @@ -1,6 +1,6 @@ import { displayNsec } from "@/commons"; import { Spinner } from "@/components"; -import { CheckIcon } from "@/components"; +import { Check } from "@phosphor-icons/react"; import * as Checkbox from "@radix-ui/react-checkbox"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { invoke } from "@tauri-apps/api/core"; @@ -101,7 +101,7 @@ function Screen() { @@ -127,7 +127,7 @@ function Screen() { id="confirm1" > - +