diff --git a/package-lock.json b/package-lock.json index 95978f6d..a8f5dd39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,12 @@ "workspaces": [ "plugin-runtime", "plugin-runtime-types", - "src-tauri/yaak_license", - "src-tauri/yaak_models", - "src-tauri/yaak_plugin_runtime", - "src-tauri/yaak_sse", - "src-tauri/yaak_sync", - "src-tauri/yaak_templates", + "src-tauri/yaak-license", + "src-tauri/yaak-models", + "src-tauri/yaak-plugins", + "src-tauri/yaak-sse", + "src-tauri/yaak-sync", + "src-tauri/yaak-templates", "src-web" ], "devDependencies": { @@ -3630,27 +3630,31 @@ "license": "MIT" }, "node_modules/@yaakapp-internal/license": { - "resolved": "src-tauri/yaak_license", + "resolved": "src-tauri/yaak-license", "link": true }, "node_modules/@yaakapp-internal/models": { - "resolved": "src-tauri/yaak_models", - "link": true - }, - "node_modules/@yaakapp-internal/plugin": { - "resolved": "src-tauri/yaak_plugin_runtime", + "resolved": "src-tauri/yaak-models", "link": true }, "node_modules/@yaakapp-internal/plugin-runtime": { "resolved": "plugin-runtime", "link": true }, + "node_modules/@yaakapp-internal/plugins": { + "resolved": "src-tauri/yaak-plugins", + "link": true + }, "node_modules/@yaakapp-internal/sse": { - "resolved": "src-tauri/yaak_sse", + "resolved": "src-tauri/yaak-sse", + "link": true + }, + "node_modules/@yaakapp-internal/sync": { + "resolved": "src-tauri/yaak-sync", "link": true }, "node_modules/@yaakapp-internal/templates": { - "resolved": "src-tauri/yaak_templates", + "resolved": "src-tauri/yaak-templates", "link": true }, "node_modules/@yaakapp/api": { @@ -15635,9 +15639,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -15812,23 +15816,62 @@ "typescript": "^5.6.2" } }, + "src-tauri/yaak_git": { + "name": "@yaakapp-internal/git", + "version": "1.0.0", + "extraneous": true + }, "src-tauri/yaak_license": { "name": "@yaakapp-internal/license", - "version": "1.0.0" + "version": "1.0.0", + "extraneous": true }, "src-tauri/yaak_models": { "name": "@yaakapp-internal/models", - "version": "1.0.0" + "version": "1.0.0", + "extraneous": true }, "src-tauri/yaak_plugin_runtime": { "name": "@yaakapp-internal/plugin", - "version": "1.0.0" + "version": "1.0.0", + "extraneous": true }, "src-tauri/yaak_sse": { "name": "@yaakapp-internal/sse", - "version": "1.0.0" + "version": "1.0.0", + "extraneous": true }, "src-tauri/yaak_templates": { + "name": "@yaakapp-internal/templates", + "version": "1.0.0", + "extraneous": true + }, + "src-tauri/yaak-git": { + "name": "@yaakapp-internal/git", + "version": "1.0.0", + "extraneous": true + }, + "src-tauri/yaak-license": { + "name": "@yaakapp-internal/license", + "version": "1.0.0" + }, + "src-tauri/yaak-models": { + "name": "@yaakapp-internal/models", + "version": "1.0.0" + }, + "src-tauri/yaak-plugins": { + "name": "@yaakapp-internal/plugins", + "version": "1.0.0" + }, + "src-tauri/yaak-sse": { + "name": "@yaakapp-internal/sse", + "version": "1.0.0" + }, + "src-tauri/yaak-sync": { + "name": "@yaakapp-internal/sync", + "version": "1.0.0" + }, + "src-tauri/yaak-templates": { "name": "@yaakapp-internal/templates", "version": "1.0.0" }, @@ -15888,7 +15931,8 @@ "slugify": "^1.6.6", "uuid": "^10.0.0", "whatwg-mimetype": "^4.0.0", - "xml-formatter": "^3.6.3" + "xml-formatter": "^3.6.3", + "yaml": "^2.6.1" }, "devDependencies": { "@lezer/generator": "^1.7.1", diff --git a/package.json b/package.json index a51ae20e..2354641d 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,12 @@ "workspaces": [ "plugin-runtime", "plugin-runtime-types", - "src-tauri/yaak_license", - "src-tauri/yaak_models", - "src-tauri/yaak_plugin_runtime", - "src-tauri/yaak_sse", - "src-tauri/yaak_sync", - "src-tauri/yaak_templates", + "src-tauri/yaak-license", + "src-tauri/yaak-models", + "src-tauri/yaak-plugins", + "src-tauri/yaak-sse", + "src-tauri/yaak-sync", + "src-tauri/yaak-templates", "src-web" ], "scripts": { diff --git a/plugin-runtime-types/package.json b/plugin-runtime-types/package.json index a03d75ed..8904f0c4 100644 --- a/plugin-runtime-types/package.json +++ b/plugin-runtime-types/package.json @@ -11,8 +11,8 @@ "build": "run-s build:copy-types build:tsc", "build:tsc": "tsc", "build:copy-types": "run-p build:copy-types:*", - "build:copy-types:root": "cpy --flat ../src-tauri/yaak_plugin_runtime/bindings/*.ts ./src/bindings", - "build:copy-types:next": "cpy --flat ../src-tauri/yaak_plugin_runtime/bindings/serde_json/*.ts ./src/bindings/serde_json", + "build:copy-types:root": "cpy --flat ../src-tauri/yaak-plugin-runtime/bindings/*.ts ./src/bindings", + "build:copy-types:next": "cpy --flat ../src-tauri/yaak-plugin-runtime/bindings/serde_json/*.ts ./src/bindings/serde_json", "prepublishOnly": "npm run build" }, "dependencies": { diff --git a/plugin-runtime-types/src/plugins/ImporterPlugin.ts b/plugin-runtime-types/src/plugins/ImporterPlugin.ts index 61d9217f..b9ea23a0 100644 --- a/plugin-runtime-types/src/plugins/ImporterPlugin.ts +++ b/plugin-runtime-types/src/plugins/ImporterPlugin.ts @@ -1,12 +1,13 @@ -import { Environment, Folder, HttpRequest, Workspace } from '..'; +import { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '..'; import { AtLeast } from '../helpers'; import { Context } from './Context'; export type ImportPluginResponse = null | { workspaces: AtLeast[]; environments: AtLeast[]; - httpRequests: AtLeast[]; folders: AtLeast[]; + httpRequests: AtLeast[]; + grpcRequests: AtLeast[]; }; export type ImporterPlugin = { diff --git a/plugin-runtime/src/PluginHandle.ts b/plugin-runtime/src/PluginHandle.ts index 8dcfecf8..4f457a9d 100644 --- a/plugin-runtime/src/PluginHandle.ts +++ b/plugin-runtime/src/PluginHandle.ts @@ -1,4 +1,4 @@ -import { BootRequest, InternalEvent } from '@yaakapp-internal/plugin'; +import { BootRequest, InternalEvent } from '@yaakapp-internal/plugins'; import path from 'node:path'; import { Worker } from 'node:worker_threads'; import { EventChannel } from './EventChannel'; diff --git a/plugin-runtime/src/index.worker.ts b/plugin-runtime/src/index.worker.ts index 0e76ac84..a1ccc290 100644 --- a/plugin-runtime/src/index.worker.ts +++ b/plugin-runtime/src/index.worker.ts @@ -12,7 +12,7 @@ import { TemplateFunction, TemplateRenderResponse, WindowContext, -} from '@yaakapp-internal/plugin'; +} from '@yaakapp-internal/plugins'; import { Context } from '@yaakapp/api'; import { HttpRequestActionPlugin } from '@yaakapp/api/lib/plugins/HttpRequestActionPlugin'; import { TemplateFunctionPlugin } from '@yaakapp/api/lib/plugins/TemplateFunctionPlugin'; diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5fcdd9f4..b4b7ccdd 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.7.8" @@ -504,7 +510,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -620,7 +626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" dependencies = [ "once_cell", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.87", @@ -795,7 +801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" dependencies = [ "serde", - "toml 0.8.2", + "toml 0.8.19", ] [[package]] @@ -1216,37 +1222,14 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", -] - [[package]] name = "darling" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] @@ -1263,24 +1246,13 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote", - "syn 1.0.109", -] - [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.10", + "darling_core", "quote", "syn 2.0.87", ] @@ -1503,7 +1475,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.2", + "toml 0.8.19", "vswhom", "winreg", ] @@ -1649,7 +1621,7 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.7.4", "rayon-core", "smallvec", "zune-inflate", @@ -1722,12 +1694,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -2165,7 +2137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ "heck 0.4.1", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -2557,7 +2529,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.3", + "webpki-roots", ] [[package]] @@ -3065,9 +3037,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -3236,6 +3208,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.1" @@ -3274,6 +3255,15 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -3471,7 +3461,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.87", @@ -4173,7 +4163,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.4", ] [[package]] @@ -4234,11 +4224,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime", "toml_edit 0.20.2", ] @@ -4550,9 +4539,9 @@ dependencies = [ [[package]] name = "r2d2_sqlite" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a982edf65c129796dba72f8775b292ef482b40d035e827a9825b3bc07ccc5f2" +checksum = "eb14dba8247a6a15b7fdbc7d389e2e6f03ee9f184f87117706d509c092dfe846" dependencies = [ "r2d2", "rusqlite", @@ -4844,7 +4833,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.3", + "webpki-roots", "winreg", ] @@ -4958,9 +4947,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.31.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ "bitflags 2.6.0", "chrono", @@ -5195,34 +5184,22 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.31.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5073b2cfed767511a57d18115f3b3d8bcb5690bf8c89518caec6cb22c0cd74" +checksum = "085e94f7d7271c0393ac2d164a39994b1dff1b06bc40cd9a0da04f3d672b0fee" dependencies = [ "chrono", "inherent", - "sea-query-attr", "sea-query-derive", ] -[[package]] -name = "sea-query-attr" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168a31e0ef5a791ad26aa97c502eaed8d2a1ffdc22b3249f9947c1e12be6b477" -dependencies = [ - "darling 0.14.4", - "heck 0.4.1", - "quote", - "syn 1.0.109", -] - [[package]] name = "sea-query-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" dependencies = [ + "darling", "heck 0.4.1", "proc-macro2", "quote", @@ -5232,9 +5209,9 @@ dependencies = [ [[package]] name = "sea-query-rusqlite" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd26649cda07604727e01106ca109e4d0796a6d09c627eaa7831fbe46daf78b" +checksum = "3743bbdfb24b1a84cc1a6fbf4b1188e6851f6e00ea20944b44c56bf03a585bb4" dependencies = [ "rusqlite", "sea-query", @@ -5418,12 +5395,25 @@ version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ - "darling 0.20.10", + "darling", "proc-macro2", "quote", "syn 2.0.87", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.3.0", + "itoa 1.0.11", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serialize-to-javascript" version = "0.1.1" @@ -5642,9 +5632,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -5655,9 +5645,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "byteorder", @@ -5680,8 +5670,8 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls 0.23.12", + "rustls-pemfile 2.1.3", "serde", "serde_json", "sha2", @@ -5692,14 +5682,14 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.25.4", + "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", @@ -5710,9 +5700,9 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -5736,9 +5726,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", @@ -5778,9 +5768,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", @@ -5816,9 +5806,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "flume", @@ -5994,7 +5984,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.2", + "toml 0.8.19", "version-compare", ] @@ -6111,7 +6101,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.7", "tokio", "tray-icon", "url", @@ -6140,7 +6130,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.8.2", + "toml 0.8.19", "walkdir", ] @@ -6164,7 +6154,7 @@ dependencies = [ "sha2", "syn 2.0.87", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.7", "time", "url", "uuid", @@ -6198,7 +6188,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.8.2", + "toml 0.8.19", "walkdir", ] @@ -6363,22 +6353,6 @@ dependencies = [ "thiserror 1.0.63", ] -[[package]] -name = "tauri-plugin-yaak-license" -version = "0.1.0" -dependencies = [ - "chrono", - "log", - "reqwest", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.3", - "ts-rs", - "yaak_models", -] - [[package]] name = "tauri-runtime" version = "2.2.0" @@ -6393,7 +6367,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.3", + "thiserror 2.0.7", "url", "windows", ] @@ -6453,8 +6427,8 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.3", - "toml 0.8.2", + "thiserror 2.0.7", + "toml 0.8.19", "url", "urlpattern", "uuid", @@ -6521,11 +6495,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.7", ] [[package]] @@ -6541,9 +6515,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", @@ -6717,21 +6691,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.22.22", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -6746,7 +6720,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -6754,12 +6728,23 @@ name = "toml_edit" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.3.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -7079,6 +7064,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -7429,12 +7420,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.3" @@ -7845,6 +7830,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.52.0" @@ -7997,21 +7991,22 @@ dependencies = [ "tauri-plugin-shell", "tauri-plugin-updater", "tauri-plugin-window-state", - "tauri-plugin-yaak-license", "tokio", "tokio-stream", "ts-rs", "urlencoding", "uuid", - "yaak_grpc", - "yaak_models", - "yaak_plugin_runtime", - "yaak_sse", - "yaak_templates", + "yaak-grpc", + "yaak-license", + "yaak-models", + "yaak-plugins", + "yaak-sse", + "yaak-sync", + "yaak-templates", ] [[package]] -name = "yaak_grpc" +name = "yaak-grpc" version = "0.1.0" dependencies = [ "anyhow", @@ -8036,14 +8031,30 @@ dependencies = [ ] [[package]] -name = "yaak_models" +name = "yaak-license" version = "0.1.0" dependencies = [ "chrono", "log", + "reqwest", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.7", + "ts-rs", + "yaak-models", +] + +[[package]] +name = "yaak-models" +version = "0.1.0" +dependencies = [ + "chrono", + "log", + "nanoid", "r2d2", "r2d2_sqlite", - "rand 0.8.5", "rusqlite", "sea-query", "sea-query-rusqlite", @@ -8056,7 +8067,7 @@ dependencies = [ ] [[package]] -name = "yaak_plugin_runtime" +name = "yaak-plugins" version = "0.1.0" dependencies = [ "dunce", @@ -8069,16 +8080,16 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin-shell", - "thiserror 1.0.63", + "thiserror 2.0.7", "tokio", "tonic 0.12.1", "tonic-build", "ts-rs", - "yaak_models", + "yaak-models", ] [[package]] -name = "yaak_sse" +name = "yaak-sse" version = "0.1.0" dependencies = [ "serde", @@ -8086,7 +8097,25 @@ dependencies = [ ] [[package]] -name = "yaak_templates" +name = "yaak-sync" +version = "0.1.0" +dependencies = [ + "chrono", + "hex", + "log", + "serde", + "serde_json", + "serde_yaml", + "sha1", + "tauri", + "tauri-plugin", + "thiserror 2.0.7", + "ts-rs", + "yaak-models", +] + +[[package]] +name = "yaak-templates" version = "0.1.0" dependencies = [ "log", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 9a2b6b15..178d43da 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,11 +1,12 @@ [workspace] members = [ - "yaak_grpc", - "yaak_license", - "yaak_models", - "yaak_plugin_runtime", - "yaak_sse", - "yaak_templates", + "yaak-grpc", + "yaak-license", + "yaak-models", + "yaak-plugins", + "yaak-sse", + "yaak-sync", + "yaak-templates", ] [package] @@ -34,15 +35,10 @@ cocoa = "0.26.0" openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work [dependencies] -yaak_grpc = { path = "yaak_grpc" } -tauri-plugin-yaak-license = { path = "yaak_license" } -yaak_models = { workspace = true } -yaak_plugin_runtime = { workspace = true } -yaak_sse = { workspace = true } -yaak_templates = { path = "yaak_templates" } base64 = "0.22.0" chrono = { version = "0.4.31", features = ["serde"] } datetime = "0.5.2" +eventsource-client = { git = "https://github.com/yaakapp/rust-eventsource-client", version = "0.13.0" } hex_color = "3.0.0" http = "1" log = "0.4.21" @@ -53,26 +49,32 @@ reqwest_cookie_store = "0.8.0" serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["raw_value"] } tauri = { workspace = true, features = ["devtools", "protocol-asset"] } -tauri-plugin-shell = { workspace = true } tauri-plugin-clipboard-manager = "2.0.1" tauri-plugin-dialog = "2.0.3" tauri-plugin-fs = "2.0.3" tauri-plugin-log = { version = "2.0.1", features = ["colored"] } tauri-plugin-os = "2.0.1" +tauri-plugin-shell = { workspace = true } tauri-plugin-updater = "2.0.2" tauri-plugin-window-state = "2.0.1" tokio = { version = "1.36.0", features = ["sync"] } tokio-stream = "0.1.15" ts-rs = { workspace = true } -uuid = "1.7.0" mime_guess = "2.0.5" urlencoding = "2.1.3" -eventsource-client = { git = "https://github.com/yaakapp/rust-eventsource-client", version = "0.13.0" } +uuid = "1.7.0" +yaak-grpc = { path = "yaak-grpc" } +yaak-license = { path = "yaak-license" } +yaak-models = { workspace = true } +yaak-plugins = { workspace = true } +yaak-sse = { workspace = true } +yaak-sync = { path = "yaak-sync" } +yaak-templates = { path = "yaak-templates" } [workspace.dependencies] -yaak_models = { path = "yaak_models" } -yaak_sse = { path = "yaak_sse" } -yaak_plugin_runtime = { path = "yaak_plugin_runtime" } +yaak-models = { path = "yaak-models" } +yaak-sse = { path = "yaak-sse" } +yaak-plugins = { path = "yaak-plugins" } serde = "1.0.215" serde_json = "1.0.132" tauri-plugin-shell = "2.0.2" diff --git a/src-tauri/capabilities/capabilities.json b/src-tauri/capabilities/capabilities.json index f37e5cb9..1e465128 100644 --- a/src-tauri/capabilities/capabilities.json +++ b/src-tauri/capabilities/capabilities.json @@ -7,7 +7,6 @@ "*" ], "permissions": [ - "yaak-license:default", "core:event:allow-emit", "core:event:allow-listen", "core:event:allow-unlisten", @@ -45,6 +44,8 @@ "core:window:allow-toggle-maximize", "core:window:allow-unmaximize", "clipboard-manager:allow-read-text", - "clipboard-manager:allow-write-text" + "clipboard-manager:allow-write-text", + "yaak-license:default", + "yaak-sync:default" ] } diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json index ef92e044..61bc7ff1 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":{"default_permission":{"identifier":"default","description":"Default core plugins set which includes:\n- 'core:path:default'\n- 'core:event:default'\n- 'core:window:default'\n- 'core:webview:default'\n- 'core:app:default'\n- 'core:image:default'\n- 'core:resources:default'\n- 'core:menu:default'\n- 'core:tray:default'\n","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version"]},"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-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-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-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-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-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-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-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-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-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-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-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-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-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-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-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-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-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-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","scope-app-index"],"deny":[]}},"deny-copy-file":{"identifier":"deny-copy-file","description":"Denies the copy_file command without any pre-configured scope.","commands":{"allow":[],"deny":["copy_file"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-exists":{"identifier":"deny-exists","description":"Denies the exists command without any pre-configured scope.","commands":{"allow":[],"deny":["exists"]}},"deny-fstat":{"identifier":"deny-fstat","description":"Denies the fstat command without any pre-configured scope.","commands":{"allow":[],"deny":["fstat"]}},"deny-ftruncate":{"identifier":"deny-ftruncate","description":"Denies the ftruncate command without any pre-configured scope.","commands":{"allow":[],"deny":["ftruncate"]}},"deny-lstat":{"identifier":"deny-lstat","description":"Denies the lstat command without any pre-configured scope.","commands":{"allow":[],"deny":["lstat"]}},"deny-mkdir":{"identifier":"deny-mkdir","description":"Denies the mkdir command without any pre-configured scope.","commands":{"allow":[],"deny":["mkdir"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-read":{"identifier":"deny-read","description":"Denies the read command without any pre-configured scope.","commands":{"allow":[],"deny":["read"]}},"deny-read-dir":{"identifier":"deny-read-dir","description":"Denies the read_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["read_dir"]}},"deny-read-file":{"identifier":"deny-read-file","description":"Denies the read_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_file"]}},"deny-read-text-file":{"identifier":"deny-read-text-file","description":"Denies the read_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file"]}},"deny-read-text-file-lines":{"identifier":"deny-read-text-file-lines","description":"Denies the read_text_file_lines command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines"]}},"deny-read-text-file-lines-next":{"identifier":"deny-read-text-file-lines-next","description":"Denies the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines_next"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-rename":{"identifier":"deny-rename","description":"Denies the rename command without any pre-configured scope.","commands":{"allow":[],"deny":["rename"]}},"deny-seek":{"identifier":"deny-seek","description":"Denies the seek command without any pre-configured scope.","commands":{"allow":[],"deny":["seek"]}},"deny-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","scope-app-recursive"],"deny":[]}},"read-dirs":{"identifier":"read-dirs","description":"This enables directory read and file metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"deny":[]}},"read-files":{"identifier":"read-files","description":"This enables file read related commands without any pre-configured accessible paths.","commands":{"allow":["read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists"],"deny":[]}},"read-meta":{"identifier":"read-meta","description":"This enables all index or metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"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 application folders.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"},{"path":"$APPDATA"},{"path":"$APPDATA/*"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"},{"path":"$APPCACHE"},{"path":"$APPCACHE/*"},{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the application directories.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete application folders, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"},{"path":"$APPDATA"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE"},{"path":"$APPCACHE/**"},{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-appcache":{"identifier":"scope-appcache","description":"This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/*"}]}},"scope-appcache-index":{"identifier":"scope-appcache-index","description":"This scope permits to list all files and folders in the `$APPCACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"}]}},"scope-appcache-recursive":{"identifier":"scope-appcache-recursive","description":"This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/**"}]}},"scope-appconfig":{"identifier":"scope-appconfig","description":"This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"}]}},"scope-appconfig-index":{"identifier":"scope-appconfig-index","description":"This scope permits to list all files and folders in the `$APPCONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"}]}},"scope-appconfig-recursive":{"identifier":"scope-appconfig-recursive","description":"This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"}]}},"scope-appdata":{"identifier":"scope-appdata","description":"This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/*"}]}},"scope-appdata-index":{"identifier":"scope-appdata-index","description":"This scope permits to list all files and folders in the `$APPDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"}]}},"scope-appdata-recursive":{"identifier":"scope-appdata-recursive","description":"This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]}},"scope-applocaldata":{"identifier":"scope-applocaldata","description":"This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"}]}},"scope-applocaldata-index":{"identifier":"scope-applocaldata-index","description":"This scope permits to list all files and folders in the `$APPLOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"}]}},"scope-applocaldata-recursive":{"identifier":"scope-applocaldata-recursive","description":"This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"}]}},"scope-applog":{"identifier":"scope-applog","description":"This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-applog-index":{"identifier":"scope-applog-index","description":"This scope permits to list all files and folders in the `$APPLOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"}]}},"scope-applog-recursive":{"identifier":"scope-applog-recursive","description":"This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-audio":{"identifier":"scope-audio","description":"This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/*"}]}},"scope-audio-index":{"identifier":"scope-audio-index","description":"This scope permits to list all files and folders in the `$AUDIO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"}]}},"scope-audio-recursive":{"identifier":"scope-audio-recursive","description":"This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/**"}]}},"scope-cache":{"identifier":"scope-cache","description":"This scope permits access to all files and list content of top level directories in the `$CACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/*"}]}},"scope-cache-index":{"identifier":"scope-cache-index","description":"This scope permits to list all files and folders in the `$CACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"}]}},"scope-cache-recursive":{"identifier":"scope-cache-recursive","description":"This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/**"}]}},"scope-config":{"identifier":"scope-config","description":"This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/*"}]}},"scope-config-index":{"identifier":"scope-config-index","description":"This scope permits to list all files and folders in the `$CONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"}]}},"scope-config-recursive":{"identifier":"scope-config-recursive","description":"This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/**"}]}},"scope-data":{"identifier":"scope-data","description":"This scope permits access to all files and list content of top level directories in the `$DATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/*"}]}},"scope-data-index":{"identifier":"scope-data-index","description":"This scope permits to list all files and folders in the `$DATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"}]}},"scope-data-recursive":{"identifier":"scope-data-recursive","description":"This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/**"}]}},"scope-desktop":{"identifier":"scope-desktop","description":"This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/*"}]}},"scope-desktop-index":{"identifier":"scope-desktop-index","description":"This scope permits to list all files and folders in the `$DESKTOP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"}]}},"scope-desktop-recursive":{"identifier":"scope-desktop-recursive","description":"This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/**"}]}},"scope-document":{"identifier":"scope-document","description":"This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/*"}]}},"scope-document-index":{"identifier":"scope-document-index","description":"This scope permits to list all files and folders in the `$DOCUMENT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"}]}},"scope-document-recursive":{"identifier":"scope-document-recursive","description":"This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/**"}]}},"scope-download":{"identifier":"scope-download","description":"This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/*"}]}},"scope-download-index":{"identifier":"scope-download-index","description":"This scope permits to list all files and folders in the `$DOWNLOAD`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"}]}},"scope-download-recursive":{"identifier":"scope-download-recursive","description":"This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/**"}]}},"scope-exe":{"identifier":"scope-exe","description":"This scope permits access to all files and list content of top level directories in the `$EXE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/*"}]}},"scope-exe-index":{"identifier":"scope-exe-index","description":"This scope permits to list all files and folders in the `$EXE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"}]}},"scope-exe-recursive":{"identifier":"scope-exe-recursive","description":"This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/**"}]}},"scope-font":{"identifier":"scope-font","description":"This scope permits access to all files and list content of top level directories in the `$FONT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/*"}]}},"scope-font-index":{"identifier":"scope-font-index","description":"This scope permits to list all files and folders in the `$FONT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"}]}},"scope-font-recursive":{"identifier":"scope-font-recursive","description":"This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/**"}]}},"scope-home":{"identifier":"scope-home","description":"This scope permits access to all files and list content of top level directories in the `$HOME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/*"}]}},"scope-home-index":{"identifier":"scope-home-index","description":"This scope permits to list all files and folders in the `$HOME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"}]}},"scope-home-recursive":{"identifier":"scope-home-recursive","description":"This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/**"}]}},"scope-localdata":{"identifier":"scope-localdata","description":"This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/*"}]}},"scope-localdata-index":{"identifier":"scope-localdata-index","description":"This scope permits to list all files and folders in the `$LOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"}]}},"scope-localdata-recursive":{"identifier":"scope-localdata-recursive","description":"This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/**"}]}},"scope-log":{"identifier":"scope-log","description":"This scope permits access to all files and list content of top level directories in the `$LOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/*"}]}},"scope-log-index":{"identifier":"scope-log-index","description":"This scope permits to list all files and folders in the `$LOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"}]}},"scope-log-recursive":{"identifier":"scope-log-recursive","description":"This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/**"}]}},"scope-picture":{"identifier":"scope-picture","description":"This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/*"}]}},"scope-picture-index":{"identifier":"scope-picture-index","description":"This scope permits to list all files and folders in the `$PICTURE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"}]}},"scope-picture-recursive":{"identifier":"scope-picture-recursive","description":"This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/**"}]}},"scope-public":{"identifier":"scope-public","description":"This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/*"}]}},"scope-public-index":{"identifier":"scope-public-index","description":"This scope permits to list all files and folders in the `$PUBLIC`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"}]}},"scope-public-recursive":{"identifier":"scope-public-recursive","description":"This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/**"}]}},"scope-resource":{"identifier":"scope-resource","description":"This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/*"}]}},"scope-resource-index":{"identifier":"scope-resource-index","description":"This scope permits to list all files and folders in the `$RESOURCE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"}]}},"scope-resource-recursive":{"identifier":"scope-resource-recursive","description":"This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/**"}]}},"scope-runtime":{"identifier":"scope-runtime","description":"This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/*"}]}},"scope-runtime-index":{"identifier":"scope-runtime-index","description":"This scope permits to list all files and folders in the `$RUNTIME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"}]}},"scope-runtime-recursive":{"identifier":"scope-runtime-recursive","description":"This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/**"}]}},"scope-temp":{"identifier":"scope-temp","description":"This scope permits access to all files and list content of top level directories in the `$TEMP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/*"}]}},"scope-temp-index":{"identifier":"scope-temp-index","description":"This scope permits to list all files and folders in the `$TEMP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"}]}},"scope-temp-recursive":{"identifier":"scope-temp-recursive","description":"This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/**"}]}},"scope-template":{"identifier":"scope-template","description":"This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/*"}]}},"scope-template-index":{"identifier":"scope-template-index","description":"This scope permits to list all files and folders in the `$TEMPLATE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"}]}},"scope-template-recursive":{"identifier":"scope-template-recursive","description":"This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/**"}]}},"scope-video":{"identifier":"scope-video","description":"This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/*"}]}},"scope-video-index":{"identifier":"scope-video-index","description":"This scope permits to list all files and folders in the `$VIDEO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"}]}},"scope-video-recursive":{"identifier":"scope-video-recursive","description":"This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/**"}]}},"write-all":{"identifier":"write-all","description":"This enables all write related commands without any pre-configured accessible paths.","commands":{"allow":["mkdir","create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}},"write-files":{"identifier":"write-files","description":"This enables all file write related commands without any pre-configured accessible paths.","commands":{"allow":["create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}}},"permission_sets":{"allow-app-meta":{"identifier":"allow-app-meta","description":"This allows non-recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-index"]},"allow-app-meta-recursive":{"identifier":"allow-app-meta-recursive","description":"This allows full recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-recursive"]},"allow-app-read":{"identifier":"allow-app-read","description":"This allows non-recursive read access to the application folders.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete application folders, files and subdirectories.","permissions":["read-all","scope-app-recursive"]},"allow-app-write":{"identifier":"allow-app-write","description":"This allows non-recursive write access to the application folders.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete application folders, files and subdirectories.","permissions":["write-all","scope-app-recursive"]},"allow-appcache-meta":{"identifier":"allow-appcache-meta","description":"This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-index"]},"allow-appcache-meta-recursive":{"identifier":"allow-appcache-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-recursive"]},"allow-appcache-read":{"identifier":"allow-appcache-read","description":"This allows non-recursive read access to the `$APPCACHE` folder.","permissions":["read-all","scope-appcache"]},"allow-appcache-read-recursive":{"identifier":"allow-appcache-read-recursive","description":"This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["read-all","scope-appcache-recursive"]},"allow-appcache-write":{"identifier":"allow-appcache-write","description":"This allows non-recursive write access to the `$APPCACHE` folder.","permissions":["write-all","scope-appcache"]},"allow-appcache-write-recursive":{"identifier":"allow-appcache-write-recursive","description":"This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["write-all","scope-appcache-recursive"]},"allow-appconfig-meta":{"identifier":"allow-appconfig-meta","description":"This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-index"]},"allow-appconfig-meta-recursive":{"identifier":"allow-appconfig-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-recursive"]},"allow-appconfig-read":{"identifier":"allow-appconfig-read","description":"This allows non-recursive read access to the `$APPCONFIG` folder.","permissions":["read-all","scope-appconfig"]},"allow-appconfig-read-recursive":{"identifier":"allow-appconfig-read-recursive","description":"This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["read-all","scope-appconfig-recursive"]},"allow-appconfig-write":{"identifier":"allow-appconfig-write","description":"This allows non-recursive write access to the `$APPCONFIG` folder.","permissions":["write-all","scope-appconfig"]},"allow-appconfig-write-recursive":{"identifier":"allow-appconfig-write-recursive","description":"This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["write-all","scope-appconfig-recursive"]},"allow-appdata-meta":{"identifier":"allow-appdata-meta","description":"This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-index"]},"allow-appdata-meta-recursive":{"identifier":"allow-appdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-recursive"]},"allow-appdata-read":{"identifier":"allow-appdata-read","description":"This allows non-recursive read access to the `$APPDATA` folder.","permissions":["read-all","scope-appdata"]},"allow-appdata-read-recursive":{"identifier":"allow-appdata-read-recursive","description":"This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["read-all","scope-appdata-recursive"]},"allow-appdata-write":{"identifier":"allow-appdata-write","description":"This allows non-recursive write access to the `$APPDATA` folder.","permissions":["write-all","scope-appdata"]},"allow-appdata-write-recursive":{"identifier":"allow-appdata-write-recursive","description":"This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["write-all","scope-appdata-recursive"]},"allow-applocaldata-meta":{"identifier":"allow-applocaldata-meta","description":"This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-index"]},"allow-applocaldata-meta-recursive":{"identifier":"allow-applocaldata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-recursive"]},"allow-applocaldata-read":{"identifier":"allow-applocaldata-read","description":"This allows non-recursive read access to the `$APPLOCALDATA` folder.","permissions":["read-all","scope-applocaldata"]},"allow-applocaldata-read-recursive":{"identifier":"allow-applocaldata-read-recursive","description":"This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-applocaldata-recursive"]},"allow-applocaldata-write":{"identifier":"allow-applocaldata-write","description":"This allows non-recursive write access to the `$APPLOCALDATA` folder.","permissions":["write-all","scope-applocaldata"]},"allow-applocaldata-write-recursive":{"identifier":"allow-applocaldata-write-recursive","description":"This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-applocaldata-recursive"]},"allow-applog-meta":{"identifier":"allow-applog-meta","description":"This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-index"]},"allow-applog-meta-recursive":{"identifier":"allow-applog-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-recursive"]},"allow-applog-read":{"identifier":"allow-applog-read","description":"This allows non-recursive read access to the `$APPLOG` folder.","permissions":["read-all","scope-applog"]},"allow-applog-read-recursive":{"identifier":"allow-applog-read-recursive","description":"This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["read-all","scope-applog-recursive"]},"allow-applog-write":{"identifier":"allow-applog-write","description":"This allows non-recursive write access to the `$APPLOG` folder.","permissions":["write-all","scope-applog"]},"allow-applog-write-recursive":{"identifier":"allow-applog-write-recursive","description":"This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["write-all","scope-applog-recursive"]},"allow-audio-meta":{"identifier":"allow-audio-meta","description":"This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-index"]},"allow-audio-meta-recursive":{"identifier":"allow-audio-meta-recursive","description":"This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-recursive"]},"allow-audio-read":{"identifier":"allow-audio-read","description":"This allows non-recursive read access to the `$AUDIO` folder.","permissions":["read-all","scope-audio"]},"allow-audio-read-recursive":{"identifier":"allow-audio-read-recursive","description":"This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["read-all","scope-audio-recursive"]},"allow-audio-write":{"identifier":"allow-audio-write","description":"This allows non-recursive write access to the `$AUDIO` folder.","permissions":["write-all","scope-audio"]},"allow-audio-write-recursive":{"identifier":"allow-audio-write-recursive","description":"This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["write-all","scope-audio-recursive"]},"allow-cache-meta":{"identifier":"allow-cache-meta","description":"This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-index"]},"allow-cache-meta-recursive":{"identifier":"allow-cache-meta-recursive","description":"This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-recursive"]},"allow-cache-read":{"identifier":"allow-cache-read","description":"This allows non-recursive read access to the `$CACHE` folder.","permissions":["read-all","scope-cache"]},"allow-cache-read-recursive":{"identifier":"allow-cache-read-recursive","description":"This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.","permissions":["read-all","scope-cache-recursive"]},"allow-cache-write":{"identifier":"allow-cache-write","description":"This allows non-recursive write access to the `$CACHE` folder.","permissions":["write-all","scope-cache"]},"allow-cache-write-recursive":{"identifier":"allow-cache-write-recursive","description":"This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.","permissions":["write-all","scope-cache-recursive"]},"allow-config-meta":{"identifier":"allow-config-meta","description":"This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-index"]},"allow-config-meta-recursive":{"identifier":"allow-config-meta-recursive","description":"This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-recursive"]},"allow-config-read":{"identifier":"allow-config-read","description":"This allows non-recursive read access to the `$CONFIG` folder.","permissions":["read-all","scope-config"]},"allow-config-read-recursive":{"identifier":"allow-config-read-recursive","description":"This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["read-all","scope-config-recursive"]},"allow-config-write":{"identifier":"allow-config-write","description":"This allows non-recursive write access to the `$CONFIG` folder.","permissions":["write-all","scope-config"]},"allow-config-write-recursive":{"identifier":"allow-config-write-recursive","description":"This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["write-all","scope-config-recursive"]},"allow-data-meta":{"identifier":"allow-data-meta","description":"This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-index"]},"allow-data-meta-recursive":{"identifier":"allow-data-meta-recursive","description":"This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-recursive"]},"allow-data-read":{"identifier":"allow-data-read","description":"This allows non-recursive read access to the `$DATA` folder.","permissions":["read-all","scope-data"]},"allow-data-read-recursive":{"identifier":"allow-data-read-recursive","description":"This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.","permissions":["read-all","scope-data-recursive"]},"allow-data-write":{"identifier":"allow-data-write","description":"This allows non-recursive write access to the `$DATA` folder.","permissions":["write-all","scope-data"]},"allow-data-write-recursive":{"identifier":"allow-data-write-recursive","description":"This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.","permissions":["write-all","scope-data-recursive"]},"allow-desktop-meta":{"identifier":"allow-desktop-meta","description":"This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-index"]},"allow-desktop-meta-recursive":{"identifier":"allow-desktop-meta-recursive","description":"This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-recursive"]},"allow-desktop-read":{"identifier":"allow-desktop-read","description":"This allows non-recursive read access to the `$DESKTOP` folder.","permissions":["read-all","scope-desktop"]},"allow-desktop-read-recursive":{"identifier":"allow-desktop-read-recursive","description":"This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["read-all","scope-desktop-recursive"]},"allow-desktop-write":{"identifier":"allow-desktop-write","description":"This allows non-recursive write access to the `$DESKTOP` folder.","permissions":["write-all","scope-desktop"]},"allow-desktop-write-recursive":{"identifier":"allow-desktop-write-recursive","description":"This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["write-all","scope-desktop-recursive"]},"allow-document-meta":{"identifier":"allow-document-meta","description":"This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-index"]},"allow-document-meta-recursive":{"identifier":"allow-document-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-recursive"]},"allow-document-read":{"identifier":"allow-document-read","description":"This allows non-recursive read access to the `$DOCUMENT` folder.","permissions":["read-all","scope-document"]},"allow-document-read-recursive":{"identifier":"allow-document-read-recursive","description":"This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["read-all","scope-document-recursive"]},"allow-document-write":{"identifier":"allow-document-write","description":"This allows non-recursive write access to the `$DOCUMENT` folder.","permissions":["write-all","scope-document"]},"allow-document-write-recursive":{"identifier":"allow-document-write-recursive","description":"This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["write-all","scope-document-recursive"]},"allow-download-meta":{"identifier":"allow-download-meta","description":"This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-index"]},"allow-download-meta-recursive":{"identifier":"allow-download-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-recursive"]},"allow-download-read":{"identifier":"allow-download-read","description":"This allows non-recursive read access to the `$DOWNLOAD` folder.","permissions":["read-all","scope-download"]},"allow-download-read-recursive":{"identifier":"allow-download-read-recursive","description":"This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["read-all","scope-download-recursive"]},"allow-download-write":{"identifier":"allow-download-write","description":"This allows non-recursive write access to the `$DOWNLOAD` folder.","permissions":["write-all","scope-download"]},"allow-download-write-recursive":{"identifier":"allow-download-write-recursive","description":"This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["write-all","scope-download-recursive"]},"allow-exe-meta":{"identifier":"allow-exe-meta","description":"This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-index"]},"allow-exe-meta-recursive":{"identifier":"allow-exe-meta-recursive","description":"This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-recursive"]},"allow-exe-read":{"identifier":"allow-exe-read","description":"This allows non-recursive read access to the `$EXE` folder.","permissions":["read-all","scope-exe"]},"allow-exe-read-recursive":{"identifier":"allow-exe-read-recursive","description":"This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.","permissions":["read-all","scope-exe-recursive"]},"allow-exe-write":{"identifier":"allow-exe-write","description":"This allows non-recursive write access to the `$EXE` folder.","permissions":["write-all","scope-exe"]},"allow-exe-write-recursive":{"identifier":"allow-exe-write-recursive","description":"This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.","permissions":["write-all","scope-exe-recursive"]},"allow-font-meta":{"identifier":"allow-font-meta","description":"This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-index"]},"allow-font-meta-recursive":{"identifier":"allow-font-meta-recursive","description":"This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-recursive"]},"allow-font-read":{"identifier":"allow-font-read","description":"This allows non-recursive read access to the `$FONT` folder.","permissions":["read-all","scope-font"]},"allow-font-read-recursive":{"identifier":"allow-font-read-recursive","description":"This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.","permissions":["read-all","scope-font-recursive"]},"allow-font-write":{"identifier":"allow-font-write","description":"This allows non-recursive write access to the `$FONT` folder.","permissions":["write-all","scope-font"]},"allow-font-write-recursive":{"identifier":"allow-font-write-recursive","description":"This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.","permissions":["write-all","scope-font-recursive"]},"allow-home-meta":{"identifier":"allow-home-meta","description":"This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-index"]},"allow-home-meta-recursive":{"identifier":"allow-home-meta-recursive","description":"This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-recursive"]},"allow-home-read":{"identifier":"allow-home-read","description":"This allows non-recursive read access to the `$HOME` folder.","permissions":["read-all","scope-home"]},"allow-home-read-recursive":{"identifier":"allow-home-read-recursive","description":"This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.","permissions":["read-all","scope-home-recursive"]},"allow-home-write":{"identifier":"allow-home-write","description":"This allows non-recursive write access to the `$HOME` folder.","permissions":["write-all","scope-home"]},"allow-home-write-recursive":{"identifier":"allow-home-write-recursive","description":"This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.","permissions":["write-all","scope-home-recursive"]},"allow-localdata-meta":{"identifier":"allow-localdata-meta","description":"This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-index"]},"allow-localdata-meta-recursive":{"identifier":"allow-localdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-recursive"]},"allow-localdata-read":{"identifier":"allow-localdata-read","description":"This allows non-recursive read access to the `$LOCALDATA` folder.","permissions":["read-all","scope-localdata"]},"allow-localdata-read-recursive":{"identifier":"allow-localdata-read-recursive","description":"This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-localdata-recursive"]},"allow-localdata-write":{"identifier":"allow-localdata-write","description":"This allows non-recursive write access to the `$LOCALDATA` folder.","permissions":["write-all","scope-localdata"]},"allow-localdata-write-recursive":{"identifier":"allow-localdata-write-recursive","description":"This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-localdata-recursive"]},"allow-log-meta":{"identifier":"allow-log-meta","description":"This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-index"]},"allow-log-meta-recursive":{"identifier":"allow-log-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-recursive"]},"allow-log-read":{"identifier":"allow-log-read","description":"This allows non-recursive read access to the `$LOG` folder.","permissions":["read-all","scope-log"]},"allow-log-read-recursive":{"identifier":"allow-log-read-recursive","description":"This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.","permissions":["read-all","scope-log-recursive"]},"allow-log-write":{"identifier":"allow-log-write","description":"This allows non-recursive write access to the `$LOG` folder.","permissions":["write-all","scope-log"]},"allow-log-write-recursive":{"identifier":"allow-log-write-recursive","description":"This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.","permissions":["write-all","scope-log-recursive"]},"allow-picture-meta":{"identifier":"allow-picture-meta","description":"This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-index"]},"allow-picture-meta-recursive":{"identifier":"allow-picture-meta-recursive","description":"This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-recursive"]},"allow-picture-read":{"identifier":"allow-picture-read","description":"This allows non-recursive read access to the `$PICTURE` folder.","permissions":["read-all","scope-picture"]},"allow-picture-read-recursive":{"identifier":"allow-picture-read-recursive","description":"This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["read-all","scope-picture-recursive"]},"allow-picture-write":{"identifier":"allow-picture-write","description":"This allows non-recursive write access to the `$PICTURE` folder.","permissions":["write-all","scope-picture"]},"allow-picture-write-recursive":{"identifier":"allow-picture-write-recursive","description":"This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["write-all","scope-picture-recursive"]},"allow-public-meta":{"identifier":"allow-public-meta","description":"This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-index"]},"allow-public-meta-recursive":{"identifier":"allow-public-meta-recursive","description":"This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-recursive"]},"allow-public-read":{"identifier":"allow-public-read","description":"This allows non-recursive read access to the `$PUBLIC` folder.","permissions":["read-all","scope-public"]},"allow-public-read-recursive":{"identifier":"allow-public-read-recursive","description":"This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["read-all","scope-public-recursive"]},"allow-public-write":{"identifier":"allow-public-write","description":"This allows non-recursive write access to the `$PUBLIC` folder.","permissions":["write-all","scope-public"]},"allow-public-write-recursive":{"identifier":"allow-public-write-recursive","description":"This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["write-all","scope-public-recursive"]},"allow-resource-meta":{"identifier":"allow-resource-meta","description":"This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-index"]},"allow-resource-meta-recursive":{"identifier":"allow-resource-meta-recursive","description":"This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-recursive"]},"allow-resource-read":{"identifier":"allow-resource-read","description":"This allows non-recursive read access to the `$RESOURCE` folder.","permissions":["read-all","scope-resource"]},"allow-resource-read-recursive":{"identifier":"allow-resource-read-recursive","description":"This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["read-all","scope-resource-recursive"]},"allow-resource-write":{"identifier":"allow-resource-write","description":"This allows non-recursive write access to the `$RESOURCE` folder.","permissions":["write-all","scope-resource"]},"allow-resource-write-recursive":{"identifier":"allow-resource-write-recursive","description":"This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["write-all","scope-resource-recursive"]},"allow-runtime-meta":{"identifier":"allow-runtime-meta","description":"This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-index"]},"allow-runtime-meta-recursive":{"identifier":"allow-runtime-meta-recursive","description":"This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-recursive"]},"allow-runtime-read":{"identifier":"allow-runtime-read","description":"This allows non-recursive read access to the `$RUNTIME` folder.","permissions":["read-all","scope-runtime"]},"allow-runtime-read-recursive":{"identifier":"allow-runtime-read-recursive","description":"This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["read-all","scope-runtime-recursive"]},"allow-runtime-write":{"identifier":"allow-runtime-write","description":"This allows non-recursive write access to the `$RUNTIME` folder.","permissions":["write-all","scope-runtime"]},"allow-runtime-write-recursive":{"identifier":"allow-runtime-write-recursive","description":"This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["write-all","scope-runtime-recursive"]},"allow-temp-meta":{"identifier":"allow-temp-meta","description":"This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-index"]},"allow-temp-meta-recursive":{"identifier":"allow-temp-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-recursive"]},"allow-temp-read":{"identifier":"allow-temp-read","description":"This allows non-recursive read access to the `$TEMP` folder.","permissions":["read-all","scope-temp"]},"allow-temp-read-recursive":{"identifier":"allow-temp-read-recursive","description":"This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.","permissions":["read-all","scope-temp-recursive"]},"allow-temp-write":{"identifier":"allow-temp-write","description":"This allows non-recursive write access to the `$TEMP` folder.","permissions":["write-all","scope-temp"]},"allow-temp-write-recursive":{"identifier":"allow-temp-write-recursive","description":"This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.","permissions":["write-all","scope-temp-recursive"]},"allow-template-meta":{"identifier":"allow-template-meta","description":"This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-index"]},"allow-template-meta-recursive":{"identifier":"allow-template-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-recursive"]},"allow-template-read":{"identifier":"allow-template-read","description":"This allows non-recursive read access to the `$TEMPLATE` folder.","permissions":["read-all","scope-template"]},"allow-template-read-recursive":{"identifier":"allow-template-read-recursive","description":"This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["read-all","scope-template-recursive"]},"allow-template-write":{"identifier":"allow-template-write","description":"This allows non-recursive write access to the `$TEMPLATE` folder.","permissions":["write-all","scope-template"]},"allow-template-write-recursive":{"identifier":"allow-template-write-recursive","description":"This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["write-all","scope-template-recursive"]},"allow-video-meta":{"identifier":"allow-video-meta","description":"This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-index"]},"allow-video-meta-recursive":{"identifier":"allow-video-meta-recursive","description":"This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-recursive"]},"allow-video-read":{"identifier":"allow-video-read","description":"This allows non-recursive read access to the `$VIDEO` folder.","permissions":["read-all","scope-video"]},"allow-video-read-recursive":{"identifier":"allow-video-read-recursive","description":"This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["read-all","scope-video-recursive"]},"allow-video-write":{"identifier":"allow-video-write","description":"This allows non-recursive write access to the `$VIDEO` folder.","permissions":["write-all","scope-video"]},"allow-video-write-recursive":{"identifier":"allow-video-write-recursive","description":"This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["write-all","scope-video-recursive"]},"deny-default":{"identifier":"deny-default","description":"This denies access to dangerous Tauri relevant files and folders by default.","permissions":["deny-webview-data-linux","deny-webview-data-windows"]}},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"FS scope path.","type":"string"},{"properties":{"path":{"description":"FS scope path.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"log":{"default_permission":{"identifier":"default","description":"Allows the log command","permissions":["allow-log"]},"permissions":{"allow-log":{"identifier":"allow-log","description":"Enables the log command without any pre-configured scope.","commands":{"allow":["log"],"deny":[]}},"deny-log":{"identifier":"deny-log","description":"Denies the log command without any pre-configured scope.","commands":{"allow":[],"deny":["log"]}}},"permission_sets":{},"global_scope_schema":null},"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},"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#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}},"updater":{"default_permission":{"identifier":"default","description":"This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n","permissions":["allow-check","allow-download","allow-install","allow-download-and-install"]},"permissions":{"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-download-and-install":{"identifier":"allow-download-and-install","description":"Enables the download_and_install command without any pre-configured scope.","commands":{"allow":["download_and_install"],"deny":[]}},"allow-install":{"identifier":"allow-install","description":"Enables the install command without any pre-configured scope.","commands":{"allow":["install"],"deny":[]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-download-and-install":{"identifier":"deny-download-and-install","description":"Denies the download_and_install command without any pre-configured scope.","commands":{"allow":[],"deny":["download_and_install"]}},"deny-install":{"identifier":"deny-install","description":"Denies the install command without any pre-configured scope.","commands":{"allow":[],"deny":["install"]}}},"permission_sets":{},"global_scope_schema":null},"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},"yaak-license":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin","permissions":["allow-check","allow-activate"]},"permissions":{"allow-activate":{"identifier":"allow-activate","description":"Enables the activate command without any pre-configured scope.","commands":{"allow":["activate"],"deny":[]}},"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"deny-activate":{"identifier":"deny-activate","description":"Denies the activate command without any pre-configured scope.","commands":{"allow":[],"deny":["activate"]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}}},"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":{"default_permission":{"identifier":"default","description":"Default core plugins set which includes:\n- 'core:path:default'\n- 'core:event:default'\n- 'core:window:default'\n- 'core:webview:default'\n- 'core:app:default'\n- 'core:image:default'\n- 'core:resources:default'\n- 'core:menu:default'\n- 'core:tray:default'\n","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version"]},"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-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-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-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-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-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-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-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-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-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-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-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-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-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-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-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-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-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-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","scope-app-index"],"deny":[]}},"deny-copy-file":{"identifier":"deny-copy-file","description":"Denies the copy_file command without any pre-configured scope.","commands":{"allow":[],"deny":["copy_file"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-exists":{"identifier":"deny-exists","description":"Denies the exists command without any pre-configured scope.","commands":{"allow":[],"deny":["exists"]}},"deny-fstat":{"identifier":"deny-fstat","description":"Denies the fstat command without any pre-configured scope.","commands":{"allow":[],"deny":["fstat"]}},"deny-ftruncate":{"identifier":"deny-ftruncate","description":"Denies the ftruncate command without any pre-configured scope.","commands":{"allow":[],"deny":["ftruncate"]}},"deny-lstat":{"identifier":"deny-lstat","description":"Denies the lstat command without any pre-configured scope.","commands":{"allow":[],"deny":["lstat"]}},"deny-mkdir":{"identifier":"deny-mkdir","description":"Denies the mkdir command without any pre-configured scope.","commands":{"allow":[],"deny":["mkdir"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-read":{"identifier":"deny-read","description":"Denies the read command without any pre-configured scope.","commands":{"allow":[],"deny":["read"]}},"deny-read-dir":{"identifier":"deny-read-dir","description":"Denies the read_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["read_dir"]}},"deny-read-file":{"identifier":"deny-read-file","description":"Denies the read_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_file"]}},"deny-read-text-file":{"identifier":"deny-read-text-file","description":"Denies the read_text_file command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file"]}},"deny-read-text-file-lines":{"identifier":"deny-read-text-file-lines","description":"Denies the read_text_file_lines command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines"]}},"deny-read-text-file-lines-next":{"identifier":"deny-read-text-file-lines-next","description":"Denies the read_text_file_lines_next command without any pre-configured scope.","commands":{"allow":[],"deny":["read_text_file_lines_next"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-rename":{"identifier":"deny-rename","description":"Denies the rename command without any pre-configured scope.","commands":{"allow":[],"deny":["rename"]}},"deny-seek":{"identifier":"deny-seek","description":"Denies the seek command without any pre-configured scope.","commands":{"allow":[],"deny":["seek"]}},"deny-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","scope-app-recursive"],"deny":[]}},"read-dirs":{"identifier":"read-dirs","description":"This enables directory read and file metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"deny":[]}},"read-files":{"identifier":"read-files","description":"This enables file read related commands without any pre-configured accessible paths.","commands":{"allow":["read_file","read","open","read_text_file","read_text_file_lines","read_text_file_lines_next","seek","stat","lstat","fstat","exists"],"deny":[]}},"read-meta":{"identifier":"read-meta","description":"This enables all index or metadata related commands without any pre-configured accessible paths.","commands":{"allow":["read_dir","stat","lstat","fstat","exists"],"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 application folders.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"},{"path":"$APPDATA"},{"path":"$APPDATA/*"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"},{"path":"$APPCACHE"},{"path":"$APPCACHE/*"},{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-app-index":{"identifier":"scope-app-index","description":"This scope permits to list all files and folders in the application directories.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPDATA"},{"path":"$APPLOCALDATA"},{"path":"$APPCACHE"},{"path":"$APPLOG"}]}},"scope-app-recursive":{"identifier":"scope-app-recursive","description":"This scope permits recursive access to the complete application folders, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"},{"path":"$APPDATA"},{"path":"$APPDATA/**"},{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"},{"path":"$APPCACHE"},{"path":"$APPCACHE/**"},{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-appcache":{"identifier":"scope-appcache","description":"This scope permits access to all files and list content of top level directories in the `$APPCACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/*"}]}},"scope-appcache-index":{"identifier":"scope-appcache-index","description":"This scope permits to list all files and folders in the `$APPCACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"}]}},"scope-appcache-recursive":{"identifier":"scope-appcache-recursive","description":"This scope permits recursive access to the complete `$APPCACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCACHE"},{"path":"$APPCACHE/**"}]}},"scope-appconfig":{"identifier":"scope-appconfig","description":"This scope permits access to all files and list content of top level directories in the `$APPCONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/*"}]}},"scope-appconfig-index":{"identifier":"scope-appconfig-index","description":"This scope permits to list all files and folders in the `$APPCONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"}]}},"scope-appconfig-recursive":{"identifier":"scope-appconfig-recursive","description":"This scope permits recursive access to the complete `$APPCONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPCONFIG"},{"path":"$APPCONFIG/**"}]}},"scope-appdata":{"identifier":"scope-appdata","description":"This scope permits access to all files and list content of top level directories in the `$APPDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/*"}]}},"scope-appdata-index":{"identifier":"scope-appdata-index","description":"This scope permits to list all files and folders in the `$APPDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"}]}},"scope-appdata-recursive":{"identifier":"scope-appdata-recursive","description":"This scope permits recursive access to the complete `$APPDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]}},"scope-applocaldata":{"identifier":"scope-applocaldata","description":"This scope permits access to all files and list content of top level directories in the `$APPLOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/*"}]}},"scope-applocaldata-index":{"identifier":"scope-applocaldata-index","description":"This scope permits to list all files and folders in the `$APPLOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"}]}},"scope-applocaldata-recursive":{"identifier":"scope-applocaldata-recursive","description":"This scope permits recursive access to the complete `$APPLOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOCALDATA"},{"path":"$APPLOCALDATA/**"}]}},"scope-applog":{"identifier":"scope-applog","description":"This scope permits access to all files and list content of top level directories in the `$APPLOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/*"}]}},"scope-applog-index":{"identifier":"scope-applog-index","description":"This scope permits to list all files and folders in the `$APPLOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"}]}},"scope-applog-recursive":{"identifier":"scope-applog-recursive","description":"This scope permits recursive access to the complete `$APPLOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$APPLOG"},{"path":"$APPLOG/**"}]}},"scope-audio":{"identifier":"scope-audio","description":"This scope permits access to all files and list content of top level directories in the `$AUDIO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/*"}]}},"scope-audio-index":{"identifier":"scope-audio-index","description":"This scope permits to list all files and folders in the `$AUDIO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"}]}},"scope-audio-recursive":{"identifier":"scope-audio-recursive","description":"This scope permits recursive access to the complete `$AUDIO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$AUDIO"},{"path":"$AUDIO/**"}]}},"scope-cache":{"identifier":"scope-cache","description":"This scope permits access to all files and list content of top level directories in the `$CACHE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/*"}]}},"scope-cache-index":{"identifier":"scope-cache-index","description":"This scope permits to list all files and folders in the `$CACHE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"}]}},"scope-cache-recursive":{"identifier":"scope-cache-recursive","description":"This scope permits recursive access to the complete `$CACHE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CACHE"},{"path":"$CACHE/**"}]}},"scope-config":{"identifier":"scope-config","description":"This scope permits access to all files and list content of top level directories in the `$CONFIG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/*"}]}},"scope-config-index":{"identifier":"scope-config-index","description":"This scope permits to list all files and folders in the `$CONFIG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"}]}},"scope-config-recursive":{"identifier":"scope-config-recursive","description":"This scope permits recursive access to the complete `$CONFIG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$CONFIG"},{"path":"$CONFIG/**"}]}},"scope-data":{"identifier":"scope-data","description":"This scope permits access to all files and list content of top level directories in the `$DATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/*"}]}},"scope-data-index":{"identifier":"scope-data-index","description":"This scope permits to list all files and folders in the `$DATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"}]}},"scope-data-recursive":{"identifier":"scope-data-recursive","description":"This scope permits recursive access to the complete `$DATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DATA"},{"path":"$DATA/**"}]}},"scope-desktop":{"identifier":"scope-desktop","description":"This scope permits access to all files and list content of top level directories in the `$DESKTOP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/*"}]}},"scope-desktop-index":{"identifier":"scope-desktop-index","description":"This scope permits to list all files and folders in the `$DESKTOP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"}]}},"scope-desktop-recursive":{"identifier":"scope-desktop-recursive","description":"This scope permits recursive access to the complete `$DESKTOP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DESKTOP"},{"path":"$DESKTOP/**"}]}},"scope-document":{"identifier":"scope-document","description":"This scope permits access to all files and list content of top level directories in the `$DOCUMENT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/*"}]}},"scope-document-index":{"identifier":"scope-document-index","description":"This scope permits to list all files and folders in the `$DOCUMENT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"}]}},"scope-document-recursive":{"identifier":"scope-document-recursive","description":"This scope permits recursive access to the complete `$DOCUMENT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOCUMENT"},{"path":"$DOCUMENT/**"}]}},"scope-download":{"identifier":"scope-download","description":"This scope permits access to all files and list content of top level directories in the `$DOWNLOAD` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/*"}]}},"scope-download-index":{"identifier":"scope-download-index","description":"This scope permits to list all files and folders in the `$DOWNLOAD`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"}]}},"scope-download-recursive":{"identifier":"scope-download-recursive","description":"This scope permits recursive access to the complete `$DOWNLOAD` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$DOWNLOAD"},{"path":"$DOWNLOAD/**"}]}},"scope-exe":{"identifier":"scope-exe","description":"This scope permits access to all files and list content of top level directories in the `$EXE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/*"}]}},"scope-exe-index":{"identifier":"scope-exe-index","description":"This scope permits to list all files and folders in the `$EXE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"}]}},"scope-exe-recursive":{"identifier":"scope-exe-recursive","description":"This scope permits recursive access to the complete `$EXE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$EXE"},{"path":"$EXE/**"}]}},"scope-font":{"identifier":"scope-font","description":"This scope permits access to all files and list content of top level directories in the `$FONT` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/*"}]}},"scope-font-index":{"identifier":"scope-font-index","description":"This scope permits to list all files and folders in the `$FONT`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"}]}},"scope-font-recursive":{"identifier":"scope-font-recursive","description":"This scope permits recursive access to the complete `$FONT` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$FONT"},{"path":"$FONT/**"}]}},"scope-home":{"identifier":"scope-home","description":"This scope permits access to all files and list content of top level directories in the `$HOME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/*"}]}},"scope-home-index":{"identifier":"scope-home-index","description":"This scope permits to list all files and folders in the `$HOME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"}]}},"scope-home-recursive":{"identifier":"scope-home-recursive","description":"This scope permits recursive access to the complete `$HOME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$HOME"},{"path":"$HOME/**"}]}},"scope-localdata":{"identifier":"scope-localdata","description":"This scope permits access to all files and list content of top level directories in the `$LOCALDATA` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/*"}]}},"scope-localdata-index":{"identifier":"scope-localdata-index","description":"This scope permits to list all files and folders in the `$LOCALDATA`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"}]}},"scope-localdata-recursive":{"identifier":"scope-localdata-recursive","description":"This scope permits recursive access to the complete `$LOCALDATA` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOCALDATA"},{"path":"$LOCALDATA/**"}]}},"scope-log":{"identifier":"scope-log","description":"This scope permits access to all files and list content of top level directories in the `$LOG` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/*"}]}},"scope-log-index":{"identifier":"scope-log-index","description":"This scope permits to list all files and folders in the `$LOG`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"}]}},"scope-log-recursive":{"identifier":"scope-log-recursive","description":"This scope permits recursive access to the complete `$LOG` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$LOG"},{"path":"$LOG/**"}]}},"scope-picture":{"identifier":"scope-picture","description":"This scope permits access to all files and list content of top level directories in the `$PICTURE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/*"}]}},"scope-picture-index":{"identifier":"scope-picture-index","description":"This scope permits to list all files and folders in the `$PICTURE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"}]}},"scope-picture-recursive":{"identifier":"scope-picture-recursive","description":"This scope permits recursive access to the complete `$PICTURE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PICTURE"},{"path":"$PICTURE/**"}]}},"scope-public":{"identifier":"scope-public","description":"This scope permits access to all files and list content of top level directories in the `$PUBLIC` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/*"}]}},"scope-public-index":{"identifier":"scope-public-index","description":"This scope permits to list all files and folders in the `$PUBLIC`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"}]}},"scope-public-recursive":{"identifier":"scope-public-recursive","description":"This scope permits recursive access to the complete `$PUBLIC` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$PUBLIC"},{"path":"$PUBLIC/**"}]}},"scope-resource":{"identifier":"scope-resource","description":"This scope permits access to all files and list content of top level directories in the `$RESOURCE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/*"}]}},"scope-resource-index":{"identifier":"scope-resource-index","description":"This scope permits to list all files and folders in the `$RESOURCE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"}]}},"scope-resource-recursive":{"identifier":"scope-resource-recursive","description":"This scope permits recursive access to the complete `$RESOURCE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RESOURCE"},{"path":"$RESOURCE/**"}]}},"scope-runtime":{"identifier":"scope-runtime","description":"This scope permits access to all files and list content of top level directories in the `$RUNTIME` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/*"}]}},"scope-runtime-index":{"identifier":"scope-runtime-index","description":"This scope permits to list all files and folders in the `$RUNTIME`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"}]}},"scope-runtime-recursive":{"identifier":"scope-runtime-recursive","description":"This scope permits recursive access to the complete `$RUNTIME` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$RUNTIME"},{"path":"$RUNTIME/**"}]}},"scope-temp":{"identifier":"scope-temp","description":"This scope permits access to all files and list content of top level directories in the `$TEMP` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/*"}]}},"scope-temp-index":{"identifier":"scope-temp-index","description":"This scope permits to list all files and folders in the `$TEMP`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"}]}},"scope-temp-recursive":{"identifier":"scope-temp-recursive","description":"This scope permits recursive access to the complete `$TEMP` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMP"},{"path":"$TEMP/**"}]}},"scope-template":{"identifier":"scope-template","description":"This scope permits access to all files and list content of top level directories in the `$TEMPLATE` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/*"}]}},"scope-template-index":{"identifier":"scope-template-index","description":"This scope permits to list all files and folders in the `$TEMPLATE`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"}]}},"scope-template-recursive":{"identifier":"scope-template-recursive","description":"This scope permits recursive access to the complete `$TEMPLATE` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$TEMPLATE"},{"path":"$TEMPLATE/**"}]}},"scope-video":{"identifier":"scope-video","description":"This scope permits access to all files and list content of top level directories in the `$VIDEO` folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/*"}]}},"scope-video-index":{"identifier":"scope-video-index","description":"This scope permits to list all files and folders in the `$VIDEO`folder.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"}]}},"scope-video-recursive":{"identifier":"scope-video-recursive","description":"This scope permits recursive access to the complete `$VIDEO` folder, including sub directories and files.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"path":"$VIDEO"},{"path":"$VIDEO/**"}]}},"write-all":{"identifier":"write-all","description":"This enables all write related commands without any pre-configured accessible paths.","commands":{"allow":["mkdir","create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}},"write-files":{"identifier":"write-files","description":"This enables all file write related commands without any pre-configured accessible paths.","commands":{"allow":["create","copy_file","remove","rename","truncate","ftruncate","write","write_file","write_text_file"],"deny":[]}}},"permission_sets":{"allow-app-meta":{"identifier":"allow-app-meta","description":"This allows non-recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-index"]},"allow-app-meta-recursive":{"identifier":"allow-app-meta-recursive","description":"This allows full recursive read access to metadata of the application folders, including file listing and statistics.","permissions":["read-meta","scope-app-recursive"]},"allow-app-read":{"identifier":"allow-app-read","description":"This allows non-recursive read access to the application folders.","permissions":["read-all","scope-app"]},"allow-app-read-recursive":{"identifier":"allow-app-read-recursive","description":"This allows full recursive read access to the complete application folders, files and subdirectories.","permissions":["read-all","scope-app-recursive"]},"allow-app-write":{"identifier":"allow-app-write","description":"This allows non-recursive write access to the application folders.","permissions":["write-all","scope-app"]},"allow-app-write-recursive":{"identifier":"allow-app-write-recursive","description":"This allows full recursive write access to the complete application folders, files and subdirectories.","permissions":["write-all","scope-app-recursive"]},"allow-appcache-meta":{"identifier":"allow-appcache-meta","description":"This allows non-recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-index"]},"allow-appcache-meta-recursive":{"identifier":"allow-appcache-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-appcache-recursive"]},"allow-appcache-read":{"identifier":"allow-appcache-read","description":"This allows non-recursive read access to the `$APPCACHE` folder.","permissions":["read-all","scope-appcache"]},"allow-appcache-read-recursive":{"identifier":"allow-appcache-read-recursive","description":"This allows full recursive read access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["read-all","scope-appcache-recursive"]},"allow-appcache-write":{"identifier":"allow-appcache-write","description":"This allows non-recursive write access to the `$APPCACHE` folder.","permissions":["write-all","scope-appcache"]},"allow-appcache-write-recursive":{"identifier":"allow-appcache-write-recursive","description":"This allows full recursive write access to the complete `$APPCACHE` folder, files and subdirectories.","permissions":["write-all","scope-appcache-recursive"]},"allow-appconfig-meta":{"identifier":"allow-appconfig-meta","description":"This allows non-recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-index"]},"allow-appconfig-meta-recursive":{"identifier":"allow-appconfig-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPCONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-appconfig-recursive"]},"allow-appconfig-read":{"identifier":"allow-appconfig-read","description":"This allows non-recursive read access to the `$APPCONFIG` folder.","permissions":["read-all","scope-appconfig"]},"allow-appconfig-read-recursive":{"identifier":"allow-appconfig-read-recursive","description":"This allows full recursive read access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["read-all","scope-appconfig-recursive"]},"allow-appconfig-write":{"identifier":"allow-appconfig-write","description":"This allows non-recursive write access to the `$APPCONFIG` folder.","permissions":["write-all","scope-appconfig"]},"allow-appconfig-write-recursive":{"identifier":"allow-appconfig-write-recursive","description":"This allows full recursive write access to the complete `$APPCONFIG` folder, files and subdirectories.","permissions":["write-all","scope-appconfig-recursive"]},"allow-appdata-meta":{"identifier":"allow-appdata-meta","description":"This allows non-recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-index"]},"allow-appdata-meta-recursive":{"identifier":"allow-appdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-appdata-recursive"]},"allow-appdata-read":{"identifier":"allow-appdata-read","description":"This allows non-recursive read access to the `$APPDATA` folder.","permissions":["read-all","scope-appdata"]},"allow-appdata-read-recursive":{"identifier":"allow-appdata-read-recursive","description":"This allows full recursive read access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["read-all","scope-appdata-recursive"]},"allow-appdata-write":{"identifier":"allow-appdata-write","description":"This allows non-recursive write access to the `$APPDATA` folder.","permissions":["write-all","scope-appdata"]},"allow-appdata-write-recursive":{"identifier":"allow-appdata-write-recursive","description":"This allows full recursive write access to the complete `$APPDATA` folder, files and subdirectories.","permissions":["write-all","scope-appdata-recursive"]},"allow-applocaldata-meta":{"identifier":"allow-applocaldata-meta","description":"This allows non-recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-index"]},"allow-applocaldata-meta-recursive":{"identifier":"allow-applocaldata-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-applocaldata-recursive"]},"allow-applocaldata-read":{"identifier":"allow-applocaldata-read","description":"This allows non-recursive read access to the `$APPLOCALDATA` folder.","permissions":["read-all","scope-applocaldata"]},"allow-applocaldata-read-recursive":{"identifier":"allow-applocaldata-read-recursive","description":"This allows full recursive read access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-applocaldata-recursive"]},"allow-applocaldata-write":{"identifier":"allow-applocaldata-write","description":"This allows non-recursive write access to the `$APPLOCALDATA` folder.","permissions":["write-all","scope-applocaldata"]},"allow-applocaldata-write-recursive":{"identifier":"allow-applocaldata-write-recursive","description":"This allows full recursive write access to the complete `$APPLOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-applocaldata-recursive"]},"allow-applog-meta":{"identifier":"allow-applog-meta","description":"This allows non-recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-index"]},"allow-applog-meta-recursive":{"identifier":"allow-applog-meta-recursive","description":"This allows full recursive read access to metadata of the `$APPLOG` folder, including file listing and statistics.","permissions":["read-meta","scope-applog-recursive"]},"allow-applog-read":{"identifier":"allow-applog-read","description":"This allows non-recursive read access to the `$APPLOG` folder.","permissions":["read-all","scope-applog"]},"allow-applog-read-recursive":{"identifier":"allow-applog-read-recursive","description":"This allows full recursive read access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["read-all","scope-applog-recursive"]},"allow-applog-write":{"identifier":"allow-applog-write","description":"This allows non-recursive write access to the `$APPLOG` folder.","permissions":["write-all","scope-applog"]},"allow-applog-write-recursive":{"identifier":"allow-applog-write-recursive","description":"This allows full recursive write access to the complete `$APPLOG` folder, files and subdirectories.","permissions":["write-all","scope-applog-recursive"]},"allow-audio-meta":{"identifier":"allow-audio-meta","description":"This allows non-recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-index"]},"allow-audio-meta-recursive":{"identifier":"allow-audio-meta-recursive","description":"This allows full recursive read access to metadata of the `$AUDIO` folder, including file listing and statistics.","permissions":["read-meta","scope-audio-recursive"]},"allow-audio-read":{"identifier":"allow-audio-read","description":"This allows non-recursive read access to the `$AUDIO` folder.","permissions":["read-all","scope-audio"]},"allow-audio-read-recursive":{"identifier":"allow-audio-read-recursive","description":"This allows full recursive read access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["read-all","scope-audio-recursive"]},"allow-audio-write":{"identifier":"allow-audio-write","description":"This allows non-recursive write access to the `$AUDIO` folder.","permissions":["write-all","scope-audio"]},"allow-audio-write-recursive":{"identifier":"allow-audio-write-recursive","description":"This allows full recursive write access to the complete `$AUDIO` folder, files and subdirectories.","permissions":["write-all","scope-audio-recursive"]},"allow-cache-meta":{"identifier":"allow-cache-meta","description":"This allows non-recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-index"]},"allow-cache-meta-recursive":{"identifier":"allow-cache-meta-recursive","description":"This allows full recursive read access to metadata of the `$CACHE` folder, including file listing and statistics.","permissions":["read-meta","scope-cache-recursive"]},"allow-cache-read":{"identifier":"allow-cache-read","description":"This allows non-recursive read access to the `$CACHE` folder.","permissions":["read-all","scope-cache"]},"allow-cache-read-recursive":{"identifier":"allow-cache-read-recursive","description":"This allows full recursive read access to the complete `$CACHE` folder, files and subdirectories.","permissions":["read-all","scope-cache-recursive"]},"allow-cache-write":{"identifier":"allow-cache-write","description":"This allows non-recursive write access to the `$CACHE` folder.","permissions":["write-all","scope-cache"]},"allow-cache-write-recursive":{"identifier":"allow-cache-write-recursive","description":"This allows full recursive write access to the complete `$CACHE` folder, files and subdirectories.","permissions":["write-all","scope-cache-recursive"]},"allow-config-meta":{"identifier":"allow-config-meta","description":"This allows non-recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-index"]},"allow-config-meta-recursive":{"identifier":"allow-config-meta-recursive","description":"This allows full recursive read access to metadata of the `$CONFIG` folder, including file listing and statistics.","permissions":["read-meta","scope-config-recursive"]},"allow-config-read":{"identifier":"allow-config-read","description":"This allows non-recursive read access to the `$CONFIG` folder.","permissions":["read-all","scope-config"]},"allow-config-read-recursive":{"identifier":"allow-config-read-recursive","description":"This allows full recursive read access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["read-all","scope-config-recursive"]},"allow-config-write":{"identifier":"allow-config-write","description":"This allows non-recursive write access to the `$CONFIG` folder.","permissions":["write-all","scope-config"]},"allow-config-write-recursive":{"identifier":"allow-config-write-recursive","description":"This allows full recursive write access to the complete `$CONFIG` folder, files and subdirectories.","permissions":["write-all","scope-config-recursive"]},"allow-data-meta":{"identifier":"allow-data-meta","description":"This allows non-recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-index"]},"allow-data-meta-recursive":{"identifier":"allow-data-meta-recursive","description":"This allows full recursive read access to metadata of the `$DATA` folder, including file listing and statistics.","permissions":["read-meta","scope-data-recursive"]},"allow-data-read":{"identifier":"allow-data-read","description":"This allows non-recursive read access to the `$DATA` folder.","permissions":["read-all","scope-data"]},"allow-data-read-recursive":{"identifier":"allow-data-read-recursive","description":"This allows full recursive read access to the complete `$DATA` folder, files and subdirectories.","permissions":["read-all","scope-data-recursive"]},"allow-data-write":{"identifier":"allow-data-write","description":"This allows non-recursive write access to the `$DATA` folder.","permissions":["write-all","scope-data"]},"allow-data-write-recursive":{"identifier":"allow-data-write-recursive","description":"This allows full recursive write access to the complete `$DATA` folder, files and subdirectories.","permissions":["write-all","scope-data-recursive"]},"allow-desktop-meta":{"identifier":"allow-desktop-meta","description":"This allows non-recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-index"]},"allow-desktop-meta-recursive":{"identifier":"allow-desktop-meta-recursive","description":"This allows full recursive read access to metadata of the `$DESKTOP` folder, including file listing and statistics.","permissions":["read-meta","scope-desktop-recursive"]},"allow-desktop-read":{"identifier":"allow-desktop-read","description":"This allows non-recursive read access to the `$DESKTOP` folder.","permissions":["read-all","scope-desktop"]},"allow-desktop-read-recursive":{"identifier":"allow-desktop-read-recursive","description":"This allows full recursive read access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["read-all","scope-desktop-recursive"]},"allow-desktop-write":{"identifier":"allow-desktop-write","description":"This allows non-recursive write access to the `$DESKTOP` folder.","permissions":["write-all","scope-desktop"]},"allow-desktop-write-recursive":{"identifier":"allow-desktop-write-recursive","description":"This allows full recursive write access to the complete `$DESKTOP` folder, files and subdirectories.","permissions":["write-all","scope-desktop-recursive"]},"allow-document-meta":{"identifier":"allow-document-meta","description":"This allows non-recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-index"]},"allow-document-meta-recursive":{"identifier":"allow-document-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOCUMENT` folder, including file listing and statistics.","permissions":["read-meta","scope-document-recursive"]},"allow-document-read":{"identifier":"allow-document-read","description":"This allows non-recursive read access to the `$DOCUMENT` folder.","permissions":["read-all","scope-document"]},"allow-document-read-recursive":{"identifier":"allow-document-read-recursive","description":"This allows full recursive read access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["read-all","scope-document-recursive"]},"allow-document-write":{"identifier":"allow-document-write","description":"This allows non-recursive write access to the `$DOCUMENT` folder.","permissions":["write-all","scope-document"]},"allow-document-write-recursive":{"identifier":"allow-document-write-recursive","description":"This allows full recursive write access to the complete `$DOCUMENT` folder, files and subdirectories.","permissions":["write-all","scope-document-recursive"]},"allow-download-meta":{"identifier":"allow-download-meta","description":"This allows non-recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-index"]},"allow-download-meta-recursive":{"identifier":"allow-download-meta-recursive","description":"This allows full recursive read access to metadata of the `$DOWNLOAD` folder, including file listing and statistics.","permissions":["read-meta","scope-download-recursive"]},"allow-download-read":{"identifier":"allow-download-read","description":"This allows non-recursive read access to the `$DOWNLOAD` folder.","permissions":["read-all","scope-download"]},"allow-download-read-recursive":{"identifier":"allow-download-read-recursive","description":"This allows full recursive read access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["read-all","scope-download-recursive"]},"allow-download-write":{"identifier":"allow-download-write","description":"This allows non-recursive write access to the `$DOWNLOAD` folder.","permissions":["write-all","scope-download"]},"allow-download-write-recursive":{"identifier":"allow-download-write-recursive","description":"This allows full recursive write access to the complete `$DOWNLOAD` folder, files and subdirectories.","permissions":["write-all","scope-download-recursive"]},"allow-exe-meta":{"identifier":"allow-exe-meta","description":"This allows non-recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-index"]},"allow-exe-meta-recursive":{"identifier":"allow-exe-meta-recursive","description":"This allows full recursive read access to metadata of the `$EXE` folder, including file listing and statistics.","permissions":["read-meta","scope-exe-recursive"]},"allow-exe-read":{"identifier":"allow-exe-read","description":"This allows non-recursive read access to the `$EXE` folder.","permissions":["read-all","scope-exe"]},"allow-exe-read-recursive":{"identifier":"allow-exe-read-recursive","description":"This allows full recursive read access to the complete `$EXE` folder, files and subdirectories.","permissions":["read-all","scope-exe-recursive"]},"allow-exe-write":{"identifier":"allow-exe-write","description":"This allows non-recursive write access to the `$EXE` folder.","permissions":["write-all","scope-exe"]},"allow-exe-write-recursive":{"identifier":"allow-exe-write-recursive","description":"This allows full recursive write access to the complete `$EXE` folder, files and subdirectories.","permissions":["write-all","scope-exe-recursive"]},"allow-font-meta":{"identifier":"allow-font-meta","description":"This allows non-recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-index"]},"allow-font-meta-recursive":{"identifier":"allow-font-meta-recursive","description":"This allows full recursive read access to metadata of the `$FONT` folder, including file listing and statistics.","permissions":["read-meta","scope-font-recursive"]},"allow-font-read":{"identifier":"allow-font-read","description":"This allows non-recursive read access to the `$FONT` folder.","permissions":["read-all","scope-font"]},"allow-font-read-recursive":{"identifier":"allow-font-read-recursive","description":"This allows full recursive read access to the complete `$FONT` folder, files and subdirectories.","permissions":["read-all","scope-font-recursive"]},"allow-font-write":{"identifier":"allow-font-write","description":"This allows non-recursive write access to the `$FONT` folder.","permissions":["write-all","scope-font"]},"allow-font-write-recursive":{"identifier":"allow-font-write-recursive","description":"This allows full recursive write access to the complete `$FONT` folder, files and subdirectories.","permissions":["write-all","scope-font-recursive"]},"allow-home-meta":{"identifier":"allow-home-meta","description":"This allows non-recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-index"]},"allow-home-meta-recursive":{"identifier":"allow-home-meta-recursive","description":"This allows full recursive read access to metadata of the `$HOME` folder, including file listing and statistics.","permissions":["read-meta","scope-home-recursive"]},"allow-home-read":{"identifier":"allow-home-read","description":"This allows non-recursive read access to the `$HOME` folder.","permissions":["read-all","scope-home"]},"allow-home-read-recursive":{"identifier":"allow-home-read-recursive","description":"This allows full recursive read access to the complete `$HOME` folder, files and subdirectories.","permissions":["read-all","scope-home-recursive"]},"allow-home-write":{"identifier":"allow-home-write","description":"This allows non-recursive write access to the `$HOME` folder.","permissions":["write-all","scope-home"]},"allow-home-write-recursive":{"identifier":"allow-home-write-recursive","description":"This allows full recursive write access to the complete `$HOME` folder, files and subdirectories.","permissions":["write-all","scope-home-recursive"]},"allow-localdata-meta":{"identifier":"allow-localdata-meta","description":"This allows non-recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-index"]},"allow-localdata-meta-recursive":{"identifier":"allow-localdata-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOCALDATA` folder, including file listing and statistics.","permissions":["read-meta","scope-localdata-recursive"]},"allow-localdata-read":{"identifier":"allow-localdata-read","description":"This allows non-recursive read access to the `$LOCALDATA` folder.","permissions":["read-all","scope-localdata"]},"allow-localdata-read-recursive":{"identifier":"allow-localdata-read-recursive","description":"This allows full recursive read access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["read-all","scope-localdata-recursive"]},"allow-localdata-write":{"identifier":"allow-localdata-write","description":"This allows non-recursive write access to the `$LOCALDATA` folder.","permissions":["write-all","scope-localdata"]},"allow-localdata-write-recursive":{"identifier":"allow-localdata-write-recursive","description":"This allows full recursive write access to the complete `$LOCALDATA` folder, files and subdirectories.","permissions":["write-all","scope-localdata-recursive"]},"allow-log-meta":{"identifier":"allow-log-meta","description":"This allows non-recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-index"]},"allow-log-meta-recursive":{"identifier":"allow-log-meta-recursive","description":"This allows full recursive read access to metadata of the `$LOG` folder, including file listing and statistics.","permissions":["read-meta","scope-log-recursive"]},"allow-log-read":{"identifier":"allow-log-read","description":"This allows non-recursive read access to the `$LOG` folder.","permissions":["read-all","scope-log"]},"allow-log-read-recursive":{"identifier":"allow-log-read-recursive","description":"This allows full recursive read access to the complete `$LOG` folder, files and subdirectories.","permissions":["read-all","scope-log-recursive"]},"allow-log-write":{"identifier":"allow-log-write","description":"This allows non-recursive write access to the `$LOG` folder.","permissions":["write-all","scope-log"]},"allow-log-write-recursive":{"identifier":"allow-log-write-recursive","description":"This allows full recursive write access to the complete `$LOG` folder, files and subdirectories.","permissions":["write-all","scope-log-recursive"]},"allow-picture-meta":{"identifier":"allow-picture-meta","description":"This allows non-recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-index"]},"allow-picture-meta-recursive":{"identifier":"allow-picture-meta-recursive","description":"This allows full recursive read access to metadata of the `$PICTURE` folder, including file listing and statistics.","permissions":["read-meta","scope-picture-recursive"]},"allow-picture-read":{"identifier":"allow-picture-read","description":"This allows non-recursive read access to the `$PICTURE` folder.","permissions":["read-all","scope-picture"]},"allow-picture-read-recursive":{"identifier":"allow-picture-read-recursive","description":"This allows full recursive read access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["read-all","scope-picture-recursive"]},"allow-picture-write":{"identifier":"allow-picture-write","description":"This allows non-recursive write access to the `$PICTURE` folder.","permissions":["write-all","scope-picture"]},"allow-picture-write-recursive":{"identifier":"allow-picture-write-recursive","description":"This allows full recursive write access to the complete `$PICTURE` folder, files and subdirectories.","permissions":["write-all","scope-picture-recursive"]},"allow-public-meta":{"identifier":"allow-public-meta","description":"This allows non-recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-index"]},"allow-public-meta-recursive":{"identifier":"allow-public-meta-recursive","description":"This allows full recursive read access to metadata of the `$PUBLIC` folder, including file listing and statistics.","permissions":["read-meta","scope-public-recursive"]},"allow-public-read":{"identifier":"allow-public-read","description":"This allows non-recursive read access to the `$PUBLIC` folder.","permissions":["read-all","scope-public"]},"allow-public-read-recursive":{"identifier":"allow-public-read-recursive","description":"This allows full recursive read access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["read-all","scope-public-recursive"]},"allow-public-write":{"identifier":"allow-public-write","description":"This allows non-recursive write access to the `$PUBLIC` folder.","permissions":["write-all","scope-public"]},"allow-public-write-recursive":{"identifier":"allow-public-write-recursive","description":"This allows full recursive write access to the complete `$PUBLIC` folder, files and subdirectories.","permissions":["write-all","scope-public-recursive"]},"allow-resource-meta":{"identifier":"allow-resource-meta","description":"This allows non-recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-index"]},"allow-resource-meta-recursive":{"identifier":"allow-resource-meta-recursive","description":"This allows full recursive read access to metadata of the `$RESOURCE` folder, including file listing and statistics.","permissions":["read-meta","scope-resource-recursive"]},"allow-resource-read":{"identifier":"allow-resource-read","description":"This allows non-recursive read access to the `$RESOURCE` folder.","permissions":["read-all","scope-resource"]},"allow-resource-read-recursive":{"identifier":"allow-resource-read-recursive","description":"This allows full recursive read access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["read-all","scope-resource-recursive"]},"allow-resource-write":{"identifier":"allow-resource-write","description":"This allows non-recursive write access to the `$RESOURCE` folder.","permissions":["write-all","scope-resource"]},"allow-resource-write-recursive":{"identifier":"allow-resource-write-recursive","description":"This allows full recursive write access to the complete `$RESOURCE` folder, files and subdirectories.","permissions":["write-all","scope-resource-recursive"]},"allow-runtime-meta":{"identifier":"allow-runtime-meta","description":"This allows non-recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-index"]},"allow-runtime-meta-recursive":{"identifier":"allow-runtime-meta-recursive","description":"This allows full recursive read access to metadata of the `$RUNTIME` folder, including file listing and statistics.","permissions":["read-meta","scope-runtime-recursive"]},"allow-runtime-read":{"identifier":"allow-runtime-read","description":"This allows non-recursive read access to the `$RUNTIME` folder.","permissions":["read-all","scope-runtime"]},"allow-runtime-read-recursive":{"identifier":"allow-runtime-read-recursive","description":"This allows full recursive read access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["read-all","scope-runtime-recursive"]},"allow-runtime-write":{"identifier":"allow-runtime-write","description":"This allows non-recursive write access to the `$RUNTIME` folder.","permissions":["write-all","scope-runtime"]},"allow-runtime-write-recursive":{"identifier":"allow-runtime-write-recursive","description":"This allows full recursive write access to the complete `$RUNTIME` folder, files and subdirectories.","permissions":["write-all","scope-runtime-recursive"]},"allow-temp-meta":{"identifier":"allow-temp-meta","description":"This allows non-recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-index"]},"allow-temp-meta-recursive":{"identifier":"allow-temp-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMP` folder, including file listing and statistics.","permissions":["read-meta","scope-temp-recursive"]},"allow-temp-read":{"identifier":"allow-temp-read","description":"This allows non-recursive read access to the `$TEMP` folder.","permissions":["read-all","scope-temp"]},"allow-temp-read-recursive":{"identifier":"allow-temp-read-recursive","description":"This allows full recursive read access to the complete `$TEMP` folder, files and subdirectories.","permissions":["read-all","scope-temp-recursive"]},"allow-temp-write":{"identifier":"allow-temp-write","description":"This allows non-recursive write access to the `$TEMP` folder.","permissions":["write-all","scope-temp"]},"allow-temp-write-recursive":{"identifier":"allow-temp-write-recursive","description":"This allows full recursive write access to the complete `$TEMP` folder, files and subdirectories.","permissions":["write-all","scope-temp-recursive"]},"allow-template-meta":{"identifier":"allow-template-meta","description":"This allows non-recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-index"]},"allow-template-meta-recursive":{"identifier":"allow-template-meta-recursive","description":"This allows full recursive read access to metadata of the `$TEMPLATE` folder, including file listing and statistics.","permissions":["read-meta","scope-template-recursive"]},"allow-template-read":{"identifier":"allow-template-read","description":"This allows non-recursive read access to the `$TEMPLATE` folder.","permissions":["read-all","scope-template"]},"allow-template-read-recursive":{"identifier":"allow-template-read-recursive","description":"This allows full recursive read access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["read-all","scope-template-recursive"]},"allow-template-write":{"identifier":"allow-template-write","description":"This allows non-recursive write access to the `$TEMPLATE` folder.","permissions":["write-all","scope-template"]},"allow-template-write-recursive":{"identifier":"allow-template-write-recursive","description":"This allows full recursive write access to the complete `$TEMPLATE` folder, files and subdirectories.","permissions":["write-all","scope-template-recursive"]},"allow-video-meta":{"identifier":"allow-video-meta","description":"This allows non-recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-index"]},"allow-video-meta-recursive":{"identifier":"allow-video-meta-recursive","description":"This allows full recursive read access to metadata of the `$VIDEO` folder, including file listing and statistics.","permissions":["read-meta","scope-video-recursive"]},"allow-video-read":{"identifier":"allow-video-read","description":"This allows non-recursive read access to the `$VIDEO` folder.","permissions":["read-all","scope-video"]},"allow-video-read-recursive":{"identifier":"allow-video-read-recursive","description":"This allows full recursive read access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["read-all","scope-video-recursive"]},"allow-video-write":{"identifier":"allow-video-write","description":"This allows non-recursive write access to the `$VIDEO` folder.","permissions":["write-all","scope-video"]},"allow-video-write-recursive":{"identifier":"allow-video-write-recursive","description":"This allows full recursive write access to the complete `$VIDEO` folder, files and subdirectories.","permissions":["write-all","scope-video-recursive"]},"deny-default":{"identifier":"deny-default","description":"This denies access to dangerous Tauri relevant files and folders by default.","permissions":["deny-webview-data-linux","deny-webview-data-windows"]}},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"description":"FS scope path.","type":"string"},{"properties":{"path":{"description":"FS scope path.","type":"string"}},"required":["path"],"type":"object"}],"description":"FS scope entry.","title":"FsScopeEntry"}},"log":{"default_permission":{"identifier":"default","description":"Allows the log command","permissions":["allow-log"]},"permissions":{"allow-log":{"identifier":"allow-log","description":"Enables the log command without any pre-configured scope.","commands":{"allow":["log"],"deny":[]}},"deny-log":{"identifier":"deny-log","description":"Denies the log command without any pre-configured scope.","commands":{"allow":[],"deny":["log"]}}},"permission_sets":{},"global_scope_schema":null},"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},"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#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}},"updater":{"default_permission":{"identifier":"default","description":"This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n","permissions":["allow-check","allow-download","allow-install","allow-download-and-install"]},"permissions":{"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-download-and-install":{"identifier":"allow-download-and-install","description":"Enables the download_and_install command without any pre-configured scope.","commands":{"allow":["download_and_install"],"deny":[]}},"allow-install":{"identifier":"allow-install","description":"Enables the install command without any pre-configured scope.","commands":{"allow":["install"],"deny":[]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-download-and-install":{"identifier":"deny-download-and-install","description":"Denies the download_and_install command without any pre-configured scope.","commands":{"allow":[],"deny":["download_and_install"]}},"deny-install":{"identifier":"deny-install","description":"Denies the install command without any pre-configured scope.","commands":{"allow":[],"deny":["install"]}}},"permission_sets":{},"global_scope_schema":null},"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},"yaak-license":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin","permissions":["allow-check","allow-activate"]},"permissions":{"allow-activate":{"identifier":"allow-activate","description":"Enables the activate command without any pre-configured scope.","commands":{"allow":["activate"],"deny":[]}},"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"deny-activate":{"identifier":"deny-activate","description":"Denies the activate command without any pre-configured scope.","commands":{"allow":[],"deny":["activate"]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}}},"permission_sets":{},"global_scope_schema":null},"yaak-sync":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin","permissions":["allow-calculate","allow-apply"]},"permissions":{"allow-activate":{"identifier":"allow-activate","description":"Enables the activate command without any pre-configured scope.","commands":{"allow":["activate"],"deny":[]}},"allow-add":{"identifier":"allow-add","description":"Enables the add command without any pre-configured scope.","commands":{"allow":["add"],"deny":[]}},"allow-apply":{"identifier":"allow-apply","description":"Enables the apply command without any pre-configured scope.","commands":{"allow":["apply"],"deny":[]}},"allow-calculate":{"identifier":"allow-calculate","description":"Enables the calculate command without any pre-configured scope.","commands":{"allow":["calculate"],"deny":[]}},"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"allow-checkout":{"identifier":"allow-checkout","description":"Enables the checkout command without any pre-configured scope.","commands":{"allow":["checkout"],"deny":[]}},"allow-cmd-add":{"identifier":"allow-cmd-add","description":"Enables the cmd_add command without any pre-configured scope.","commands":{"allow":["cmd_add"],"deny":[]}},"allow-cmd-checkout":{"identifier":"allow-cmd-checkout","description":"Enables the cmd_checkout command without any pre-configured scope.","commands":{"allow":["cmd_checkout"],"deny":[]}},"allow-cmd-commit":{"identifier":"allow-cmd-commit","description":"Enables the cmd_commit command without any pre-configured scope.","commands":{"allow":["cmd_commit"],"deny":[]}},"allow-cmd-init":{"identifier":"allow-cmd-init","description":"Enables the cmd_init command without any pre-configured scope.","commands":{"allow":["cmd_init"],"deny":[]}},"allow-cmd-log":{"identifier":"allow-cmd-log","description":"Enables the cmd_log command without any pre-configured scope.","commands":{"allow":["cmd_log"],"deny":[]}},"allow-cmd-status":{"identifier":"allow-cmd-status","description":"Enables the cmd_status command without any pre-configured scope.","commands":{"allow":["cmd_status"],"deny":[]}},"allow-commit":{"identifier":"allow-commit","description":"Enables the commit command without any pre-configured scope.","commands":{"allow":["commit"],"deny":[]}},"allow-init":{"identifier":"allow-init","description":"Enables the init command without any pre-configured scope.","commands":{"allow":["init"],"deny":[]}},"allow-init-repo":{"identifier":"allow-init-repo","description":"Enables the init_repo command without any pre-configured scope.","commands":{"allow":["init_repo"],"deny":[]}},"allow-initialize":{"identifier":"allow-initialize","description":"Enables the initialize command without any pre-configured scope.","commands":{"allow":["initialize"],"deny":[]}},"allow-log":{"identifier":"allow-log","description":"Enables the log command without any pre-configured scope.","commands":{"allow":["log"],"deny":[]}},"allow-status":{"identifier":"allow-status","description":"Enables the status command without any pre-configured scope.","commands":{"allow":["status"],"deny":[]}},"allow-sync":{"identifier":"allow-sync","description":"Enables the sync command without any pre-configured scope.","commands":{"allow":["sync"],"deny":[]}},"allow-sync-fs":{"identifier":"allow-sync-fs","description":"Enables the sync_fs command without any pre-configured scope.","commands":{"allow":["sync_fs"],"deny":[]}},"allow-unstage":{"identifier":"allow-unstage","description":"Enables the unstage command without any pre-configured scope.","commands":{"allow":["unstage"],"deny":[]}},"deny-activate":{"identifier":"deny-activate","description":"Denies the activate command without any pre-configured scope.","commands":{"allow":[],"deny":["activate"]}},"deny-add":{"identifier":"deny-add","description":"Denies the add command without any pre-configured scope.","commands":{"allow":[],"deny":["add"]}},"deny-apply":{"identifier":"deny-apply","description":"Denies the apply command without any pre-configured scope.","commands":{"allow":[],"deny":["apply"]}},"deny-calculate":{"identifier":"deny-calculate","description":"Denies the calculate command without any pre-configured scope.","commands":{"allow":[],"deny":["calculate"]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}},"deny-checkout":{"identifier":"deny-checkout","description":"Denies the checkout command without any pre-configured scope.","commands":{"allow":[],"deny":["checkout"]}},"deny-cmd-add":{"identifier":"deny-cmd-add","description":"Denies the cmd_add command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_add"]}},"deny-cmd-checkout":{"identifier":"deny-cmd-checkout","description":"Denies the cmd_checkout command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_checkout"]}},"deny-cmd-commit":{"identifier":"deny-cmd-commit","description":"Denies the cmd_commit command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_commit"]}},"deny-cmd-init":{"identifier":"deny-cmd-init","description":"Denies the cmd_init command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_init"]}},"deny-cmd-log":{"identifier":"deny-cmd-log","description":"Denies the cmd_log command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_log"]}},"deny-cmd-status":{"identifier":"deny-cmd-status","description":"Denies the cmd_status command without any pre-configured scope.","commands":{"allow":[],"deny":["cmd_status"]}},"deny-commit":{"identifier":"deny-commit","description":"Denies the commit command without any pre-configured scope.","commands":{"allow":[],"deny":["commit"]}},"deny-init":{"identifier":"deny-init","description":"Denies the init command without any pre-configured scope.","commands":{"allow":[],"deny":["init"]}},"deny-init-repo":{"identifier":"deny-init-repo","description":"Denies the init_repo command without any pre-configured scope.","commands":{"allow":[],"deny":["init_repo"]}},"deny-initialize":{"identifier":"deny-initialize","description":"Denies the initialize command without any pre-configured scope.","commands":{"allow":[],"deny":["initialize"]}},"deny-log":{"identifier":"deny-log","description":"Denies the log command without any pre-configured scope.","commands":{"allow":[],"deny":["log"]}},"deny-status":{"identifier":"deny-status","description":"Denies the status command without any pre-configured scope.","commands":{"allow":[],"deny":["status"]}},"deny-sync":{"identifier":"deny-sync","description":"Denies the sync command without any pre-configured scope.","commands":{"allow":[],"deny":["sync"]}},"deny-sync-fs":{"identifier":"deny-sync-fs","description":"Denies the sync_fs command without any pre-configured scope.","commands":{"allow":[],"deny":["sync_fs"]}},"deny-unstage":{"identifier":"deny-unstage","description":"Denies the unstage command without any pre-configured scope.","commands":{"allow":[],"deny":["unstage"]}}},"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 71581388..4c6888ed 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["yaak-license:default","core:event:allow-emit","core:event:allow-listen","core:event:allow-unlisten","os:allow-os-type","clipboard-manager:allow-clear","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open","core:webview:allow-set-webview-zoom","core:window:allow-close","core:window:allow-internal-toggle-maximize","core:window:allow-is-fullscreen","core:window:allow-maximize","core:window:allow-minimize","core:window:allow-set-decorations","core:window:allow-set-title","core:window:allow-show","core:window:allow-start-dragging","core:window:allow-theme","core:window:allow-toggle-maximize","core:window:allow-unmaximize","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text"]}} \ No newline at end of file +{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["core:event:allow-emit","core:event:allow-listen","core:event:allow-unlisten","os:allow-os-type","clipboard-manager:allow-clear","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open","core:webview:allow-set-webview-zoom","core:window:allow-close","core:window:allow-internal-toggle-maximize","core:window:allow-is-fullscreen","core:window:allow-maximize","core:window:allow-minimize","core:window:allow-set-decorations","core:window:allow-set-title","core:window:allow-show","core:window:allow-start-dragging","core:window:allow-theme","core:window:allow-toggle-maximize","core:window:allow-unmaximize","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text","yaak-license:default","yaak-sync:default"]}} \ 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 4f51bcf8..083f815a 100644 --- a/src-tauri/gen/schemas/desktop-schema.json +++ b/src-tauri/gen/schemas/desktop-schema.json @@ -5166,6 +5166,221 @@ "description": "Denies the check command without any pre-configured scope.", "type": "string", "const": "yaak-license:deny-check" + }, + { + "description": "Default permissions for the plugin", + "type": "string", + "const": "yaak-sync:default" + }, + { + "description": "Enables the activate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-activate" + }, + { + "description": "Enables the add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-add" + }, + { + "description": "Enables the apply command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-apply" + }, + { + "description": "Enables the calculate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-calculate" + }, + { + "description": "Enables the check command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-check" + }, + { + "description": "Enables the checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-checkout" + }, + { + "description": "Enables the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-add" + }, + { + "description": "Enables the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-checkout" + }, + { + "description": "Enables the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-commit" + }, + { + "description": "Enables the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-init" + }, + { + "description": "Enables the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-log" + }, + { + "description": "Enables the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-status" + }, + { + "description": "Enables the commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-commit" + }, + { + "description": "Enables the init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-init" + }, + { + "description": "Enables the init_repo command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-init-repo" + }, + { + "description": "Enables the initialize command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-initialize" + }, + { + "description": "Enables the log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-log" + }, + { + "description": "Enables the status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-status" + }, + { + "description": "Enables the sync command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-sync" + }, + { + "description": "Enables the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-sync-fs" + }, + { + "description": "Enables the unstage command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-unstage" + }, + { + "description": "Denies the activate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-activate" + }, + { + "description": "Denies the add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-add" + }, + { + "description": "Denies the apply command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-apply" + }, + { + "description": "Denies the calculate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-calculate" + }, + { + "description": "Denies the check command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-check" + }, + { + "description": "Denies the checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-checkout" + }, + { + "description": "Denies the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-add" + }, + { + "description": "Denies the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-checkout" + }, + { + "description": "Denies the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-commit" + }, + { + "description": "Denies the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-init" + }, + { + "description": "Denies the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-log" + }, + { + "description": "Denies the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-status" + }, + { + "description": "Denies the commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-commit" + }, + { + "description": "Denies the init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-init" + }, + { + "description": "Denies the init_repo command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-init-repo" + }, + { + "description": "Denies the initialize command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-initialize" + }, + { + "description": "Denies the log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-log" + }, + { + "description": "Denies the status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-status" + }, + { + "description": "Denies the sync command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-sync" + }, + { + "description": "Denies the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-sync-fs" + }, + { + "description": "Denies the unstage command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-unstage" } ] }, diff --git a/src-tauri/gen/schemas/macOS-schema.json b/src-tauri/gen/schemas/macOS-schema.json index 4f51bcf8..083f815a 100644 --- a/src-tauri/gen/schemas/macOS-schema.json +++ b/src-tauri/gen/schemas/macOS-schema.json @@ -5166,6 +5166,221 @@ "description": "Denies the check command without any pre-configured scope.", "type": "string", "const": "yaak-license:deny-check" + }, + { + "description": "Default permissions for the plugin", + "type": "string", + "const": "yaak-sync:default" + }, + { + "description": "Enables the activate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-activate" + }, + { + "description": "Enables the add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-add" + }, + { + "description": "Enables the apply command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-apply" + }, + { + "description": "Enables the calculate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-calculate" + }, + { + "description": "Enables the check command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-check" + }, + { + "description": "Enables the checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-checkout" + }, + { + "description": "Enables the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-add" + }, + { + "description": "Enables the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-checkout" + }, + { + "description": "Enables the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-commit" + }, + { + "description": "Enables the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-init" + }, + { + "description": "Enables the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-log" + }, + { + "description": "Enables the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-cmd-status" + }, + { + "description": "Enables the commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-commit" + }, + { + "description": "Enables the init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-init" + }, + { + "description": "Enables the init_repo command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-init-repo" + }, + { + "description": "Enables the initialize command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-initialize" + }, + { + "description": "Enables the log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-log" + }, + { + "description": "Enables the status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-status" + }, + { + "description": "Enables the sync command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-sync" + }, + { + "description": "Enables the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-sync-fs" + }, + { + "description": "Enables the unstage command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:allow-unstage" + }, + { + "description": "Denies the activate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-activate" + }, + { + "description": "Denies the add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-add" + }, + { + "description": "Denies the apply command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-apply" + }, + { + "description": "Denies the calculate command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-calculate" + }, + { + "description": "Denies the check command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-check" + }, + { + "description": "Denies the checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-checkout" + }, + { + "description": "Denies the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-add" + }, + { + "description": "Denies the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-checkout" + }, + { + "description": "Denies the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-commit" + }, + { + "description": "Denies the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-init" + }, + { + "description": "Denies the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-log" + }, + { + "description": "Denies the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-cmd-status" + }, + { + "description": "Denies the commit command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-commit" + }, + { + "description": "Denies the init command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-init" + }, + { + "description": "Denies the init_repo command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-init-repo" + }, + { + "description": "Denies the initialize command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-initialize" + }, + { + "description": "Denies the log command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-log" + }, + { + "description": "Denies the status command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-status" + }, + { + "description": "Denies the sync command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-sync" + }, + { + "description": "Denies the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-sync-fs" + }, + { + "description": "Denies the unstage command without any pre-configured scope.", + "type": "string", + "const": "yaak-sync:deny-unstage" } ] }, diff --git a/src-tauri/migrations/20250102141937_sync.sql b/src-tauri/migrations/20250102141937_sync.sql new file mode 100644 index 00000000..69b325eb --- /dev/null +++ b/src-tauri/migrations/20250102141937_sync.sql @@ -0,0 +1,21 @@ +ALTER TABLE workspaces + ADD COLUMN setting_sync_dir TEXT; + +CREATE TABLE sync_states +( + id TEXT NOT NULL + PRIMARY KEY, + model TEXT DEFAULT 'sync_state' NOT NULL, + workspace_id TEXT NOT NULL + REFERENCES workspaces + ON DELETE CASCADE, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + flushed_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + checksum TEXT NOT NULL, + model_id TEXT NOT NULL, + sync_dir TEXT NOT NULL, + rel_path TEXT NOT NULL, + + UNIQUE (workspace_id, model_id) +); diff --git a/src-tauri/src/analytics.rs b/src-tauri/src/analytics.rs index 284f64b8..6090a917 100644 --- a/src-tauri/src/analytics.rs +++ b/src-tauri/src/analytics.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use tauri::{Manager, Runtime, WebviewWindow}; use ts_rs::TS; -use yaak_models::queries::{generate_id, get_key_value_int, get_key_value_string, get_or_create_settings, set_key_value_int, set_key_value_string}; +use yaak_models::queries::{generate_id, get_key_value_int, get_key_value_string, get_or_create_settings, set_key_value_int, set_key_value_string, UpdateSource}; use crate::is_dev; @@ -49,11 +49,7 @@ impl AnalyticsResource { impl Display for AnalyticsResource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - serde_json::to_string(self).unwrap().replace("\"", "") - ) + write!(f, "{}", serde_json::to_string(self).unwrap().replace("\"", "")) } } @@ -89,11 +85,7 @@ impl AnalyticsAction { impl Display for AnalyticsAction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - serde_json::to_string(self).unwrap().replace("\"", "") - ) + write!(f, "{}", serde_json::to_string(self).unwrap().replace("\"", "")) } } @@ -115,13 +107,7 @@ pub async fn track_launch_event(w: &WebviewWindow) -> LaunchEvent info.current_version = w.package_info().version.to_string(); if info.previous_version.is_empty() { - track_event( - w, - AnalyticsResource::App, - AnalyticsAction::LaunchFirst, - None, - ) - .await; + track_event(w, AnalyticsResource::App, AnalyticsAction::LaunchFirst, None).await; } else { info.launched_after_update = info.current_version != info.previous_version; if info.launched_after_update { @@ -151,9 +137,11 @@ pub async fn track_launch_event(w: &WebviewWindow) -> LaunchEvent NAMESPACE, last_tracked_version_key, info.current_version.as_str(), + &UpdateSource::Background, ) .await; - set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches).await; + set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches, &UpdateSource::Background) + .await; info } @@ -164,7 +152,6 @@ pub async fn track_event( action: AnalyticsAction, attributes: Option, ) { - let id = get_id(w).await; let event = format!("{}.{}", resource, action); let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string(); @@ -188,16 +175,13 @@ pub async fn track_event( ("tz", tz), ("xy", get_window_size(w)), ]; - let req = reqwest::Client::builder() - .build() - .unwrap() - .get(format!("{base_url}/t/e")) - .query(¶ms); + let req = + reqwest::Client::builder().build().unwrap().get(format!("{base_url}/t/e")).query(¶ms); let settings = get_or_create_settings(w).await; if !settings.telemetry { info!("Track event (disabled): {}", event); - return + return; } // Disable analytics actual sending in dev @@ -234,18 +218,15 @@ fn get_window_size(w: &WebviewWindow) -> String { let width: f64 = size.width as f64 / scale_factor; let height: f64 = size.height as f64 / scale_factor; - format!( - "{}x{}", - (width / 100.0).round() * 100.0, - (height / 100.0).round() * 100.0 - ) + format!("{}x{}", (width / 100.0).round() * 100.0, (height / 100.0).round() * 100.0) } async fn get_id(w: &WebviewWindow) -> String { let id = get_key_value_string(w, "analytics", "id", "").await; if id.is_empty() { let new_id = generate_id(); - set_key_value_string(w, "analytics", "id", new_id.as_str()).await; + set_key_value_string(w, "analytics", "id", new_id.as_str(), &UpdateSource::Background) + .await; new_id } else { id diff --git a/src-tauri/src/export_resources.rs b/src-tauri/src/export_resources.rs deleted file mode 100644 index 61443508..00000000 --- a/src-tauri/src/export_resources.rs +++ /dev/null @@ -1,77 +0,0 @@ -use chrono::NaiveDateTime; -use serde::{Deserialize, Serialize}; -use tauri::{Manager, WebviewWindow}; -use yaak_models::models::{Environment, Folder, GrpcRequest, HttpRequest, Workspace}; - -#[derive(Default, Debug, Deserialize, Serialize)] -#[serde(default, rename_all = "camelCase")] -pub struct WorkspaceExport { - pub yaak_version: String, - pub yaak_schema: i64, - pub timestamp: NaiveDateTime, - pub resources: WorkspaceExportResources, -} - -#[derive(Default, Debug, Deserialize, Serialize)] -#[serde(default, rename_all = "camelCase")] -pub struct WorkspaceExportResources { - pub workspaces: Vec, - pub environments: Vec, - pub folders: Vec, - pub http_requests: Vec, - pub grpc_requests: Vec, -} - -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct ImportResult { - pub resources: WorkspaceExportResources, -} - -pub async fn get_workspace_export_resources( - window: &WebviewWindow, - workspace_ids: Vec<&str>, -) -> WorkspaceExport { - let app_handle = window.app_handle(); - let mut data = WorkspaceExport { - yaak_version: app_handle.package_info().version.clone().to_string(), - yaak_schema: 3, - timestamp: chrono::Utc::now().naive_utc(), - resources: WorkspaceExportResources { - workspaces: Vec::new(), - environments: Vec::new(), - folders: Vec::new(), - http_requests: Vec::new(), - grpc_requests: Vec::new(), - }, - }; - - for workspace_id in workspace_ids { - data.resources.workspaces.push( - yaak_models::queries::get_workspace(window, workspace_id) - .await - .expect("Failed to get workspace"), - ); - data.resources.environments.append( - &mut yaak_models::queries::list_environments(window, workspace_id) - .await - .expect("Failed to get environments"), - ); - data.resources.folders.append( - &mut yaak_models::queries::list_folders(window, workspace_id) - .await - .expect("Failed to get folders"), - ); - data.resources.http_requests.append( - &mut yaak_models::queries::list_http_requests(window, workspace_id) - .await - .expect("Failed to get http requests"), - ); - data.resources.grpc_requests.append( - &mut yaak_models::queries::list_grpc_requests(window, workspace_id) - .await - .expect("Failed to get grpc requests"), - ); - } - - return data; -} diff --git a/src-tauri/src/http_request.rs b/src-tauri/src/http_request.rs index ed2ef075..a01e3551 100644 --- a/src-tauri/src/http_request.rs +++ b/src-tauri/src/http_request.rs @@ -27,11 +27,8 @@ use yaak_models::models::{ Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader, HttpResponseState, ProxySetting, ProxySettingAuth, }; -use yaak_models::queries::{ - get_base_environment, get_http_response, get_or_create_settings, get_workspace, - update_response_if_id, upsert_cookie_jar, -}; -use yaak_plugin_runtime::events::{RenderPurpose, WindowContext}; +use yaak_models::queries::{get_base_environment, get_http_response, get_or_create_settings, get_workspace, update_response_if_id, upsert_cookie_jar, UpdateSource}; +use yaak_plugins::events::{RenderPurpose, WindowContext}; pub async fn send_http_request( window: &WebviewWindow, @@ -439,7 +436,7 @@ pub async fn send_http_request( }; r.state = HttpResponseState::Connected; - update_response_if_id(&window, &r) + update_response_if_id(&window, &r, &UpdateSource::Window) .await .expect("Failed to update response after connected"); } @@ -468,7 +465,7 @@ pub async fn send_http_request( f.flush().await.expect("Failed to flush file"); written_bytes += bytes.len(); r.content_length = Some(written_bytes as i32); - update_response_if_id(&window, &r) + update_response_if_id(&window, &r, &UpdateSource::Window) .await .expect("Failed to update response"); } @@ -490,7 +487,7 @@ pub async fn send_http_request( None => Some(written_bytes as i32), }; r.state = HttpResponseState::Closed; - update_response_if_id(&window, &r) + update_response_if_id(&window, &r, &UpdateSource::Window) .await .expect("Failed to update response"); }; @@ -516,7 +513,9 @@ pub async fn send_http_request( }) .collect::>(); cookie_jar.cookies = json_cookies; - if let Err(e) = upsert_cookie_jar(&window, &cookie_jar).await { + if let Err(e) = + upsert_cookie_jar(&window, &cookie_jar, &UpdateSource::Window).await + { error!("Failed to update cookie jar: {}", e); }; } @@ -538,7 +537,7 @@ pub async fn send_http_request( match get_http_response(window, response_id.as_str()).await { Ok(mut r) => { r.state = HttpResponseState::Closed; - update_response_if_id(&window, &r).await.expect("Failed to update response") + update_response_if_id(&window, &r, &UpdateSource::Window).await.expect("Failed to update response") }, _ => { response_err(&*response.lock().await, "Ephemeral request was cancelled".to_string(), &window).await diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index df9c66ea..5fedcd21 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -33,10 +33,8 @@ use tokio::sync::Mutex; use tokio::task::block_in_place; use yaak_grpc::manager::{DynamicMessage, GrpcHandle}; use yaak_grpc::{deserialize_message, serialize_message, Code, ServiceDefinition}; -use yaak_plugin_runtime::manager::PluginManager; use crate::analytics::{AnalyticsAction, AnalyticsResource}; -use crate::export_resources::{get_workspace_export_resources, WorkspaceExportResources}; use crate::grpc::metadata_to_map; use crate::http_request::send_http_request; use crate::notifications::YaakNotifier; @@ -50,36 +48,38 @@ use yaak_models::models::{ ModelType, Plugin, Settings, Workspace, }; use yaak_models::queries::{ - cancel_pending_grpc_connections, cancel_pending_responses, create_default_http_response, - delete_all_grpc_connections, delete_all_grpc_connections_for_workspace, - delete_all_http_responses_for_request, delete_all_http_responses_for_workspace, - delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection, - delete_grpc_request, delete_http_request, delete_http_response, delete_plugin, - delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request, - generate_id, generate_model_id, get_base_environment, get_cookie_jar, get_environment, - get_folder, get_grpc_connection, get_grpc_request, get_http_request, get_http_response, - get_key_value_raw, get_or_create_settings, get_plugin, get_workspace, list_cookie_jars, - list_environments, list_folders, list_grpc_connections_for_workspace, list_grpc_events, - list_grpc_requests, list_http_requests, list_http_responses_for_request, + batch_upsert, cancel_pending_grpc_connections, cancel_pending_responses, + create_default_http_response, delete_all_grpc_connections, + delete_all_grpc_connections_for_workspace, delete_all_http_responses_for_request, + delete_all_http_responses_for_workspace, delete_cookie_jar, delete_environment, delete_folder, + delete_grpc_connection, delete_grpc_request, delete_http_request, delete_http_response, + delete_plugin, delete_workspace, duplicate_folder, duplicate_grpc_request, + duplicate_http_request, ensure_base_environment, generate_id, generate_model_id, + get_base_environment, get_cookie_jar, get_environment, get_folder, get_grpc_connection, + get_grpc_request, get_http_request, get_http_response, get_key_value_raw, + get_or_create_settings, get_plugin, get_workspace, get_workspace_export_resources, + list_cookie_jars, list_environments, list_folders, list_grpc_connections_for_workspace, + list_grpc_events, list_grpc_requests, list_http_requests, list_http_responses_for_request, list_http_responses_for_workspace, list_key_values_raw, list_plugins, list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_event, - upsert_grpc_request, upsert_http_request, upsert_plugin, upsert_workspace, + upsert_grpc_request, upsert_http_request, upsert_plugin, upsert_workspace, BatchUpsertResult, + UpdateSource, }; -use yaak_plugin_runtime::events::{ +use yaak_plugins::events::{ BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse, GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, Icon, InternalEvent, InternalEventPayload, PromptTextResponse, RenderHttpRequestResponse, RenderPurpose, SendHttpRequestResponse, ShowToastRequest, TemplateRenderResponse, WindowContext, }; -use yaak_plugin_runtime::plugin_handle::PluginHandle; +use yaak_plugins::manager::PluginManager; +use yaak_plugins::plugin_handle::PluginHandle; use yaak_sse::sse::ServerSentEvent; use yaak_templates::format::format_json; use yaak_templates::{Parser, Tokens}; mod analytics; -mod export_resources; mod grpc; mod http_request; mod notifications; @@ -269,6 +269,7 @@ async fn cmd_grpc_go( url: req.url.clone(), ..Default::default() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string())? @@ -321,6 +322,7 @@ async fn cmd_grpc_go( state: GrpcConnectionState::Closed, ..conn.clone() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string())?; @@ -394,6 +396,7 @@ async fn cmd_grpc_go( content: e.to_string(), ..base_msg.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -410,6 +413,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::ClientMessage, ..base_msg.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -454,6 +458,7 @@ async fn cmd_grpc_go( metadata: metadata.clone(), ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -492,6 +497,7 @@ async fn cmd_grpc_go( content: msg, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -512,6 +518,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::Info, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -522,6 +529,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::ServerMessage, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -533,6 +541,7 @@ async fn cmd_grpc_go( status: Some(Code::Ok as i32), ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -557,12 +566,13 @@ async fn cmd_grpc_go( ..base_event.clone() }, }), + &UpdateSource::Window, ) .await .unwrap(); } None => { - // Server streaming doesn't return initial message + // Server streaming doesn't return the initial message } } @@ -581,6 +591,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::Info, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -607,6 +618,7 @@ async fn cmd_grpc_go( ..base_event.clone() }, }), + &UpdateSource::Window, ) .await .unwrap(); @@ -626,6 +638,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::ServerMessage, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -642,6 +655,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::ConnectionEnd, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -657,6 +671,7 @@ async fn cmd_grpc_go( event_type: GrpcEventType::ConnectionEnd, ..base_event.clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -687,6 +702,7 @@ async fn cmd_grpc_go( state: GrpcConnectionState::Closed, ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() }, + &UpdateSource::Window, ).await.unwrap(); }, _ = cancelled_rx.changed() => { @@ -698,6 +714,7 @@ async fn cmd_grpc_go( status: Some(Code::Cancelled as i32), ..base_msg.clone() }, + &UpdateSource::Window, ).await.unwrap(); upsert_grpc_connection( &w, @@ -707,6 +724,7 @@ async fn cmd_grpc_go( state: GrpcConnectionState::Closed, ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() }, + &UpdateSource::Window, ) .await .unwrap(); @@ -809,7 +827,7 @@ async fn cmd_import_data( window: WebviewWindow, plugin_manager: State<'_, PluginManager>, file_path: &str, -) -> Result { +) -> Result { let file = read_to_string(file_path) .await .unwrap_or_else(|_| panic!("Unable to read file {}", file_path)); @@ -817,7 +835,6 @@ async fn cmd_import_data( let (import_result, plugin_name) = plugin_manager.import_data(&window, file_contents).await.map_err(|e| e.to_string())?; - let mut imported_resources = WorkspaceExportResources::default(); let mut id_map: BTreeMap = BTreeMap::new(); fn maybe_gen_id(id: &str, model: ModelType, ids: &mut BTreeMap) -> String { @@ -848,87 +865,68 @@ async fn cmd_import_data( let resources = import_result.resources; - for mut v in resources.workspaces { - v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWorkspace, &mut id_map); - let x = upsert_workspace(&window, v).await.map_err(|e| e.to_string())?; - imported_resources.workspaces.push(x.clone()); - } - info!("Imported {} workspaces", imported_resources.workspaces.len()); + let workspaces: Vec = resources + .workspaces + .into_iter() + .map(|mut v| { + v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWorkspace, &mut id_map); + v + }) + .collect(); - // Environments can foreign-key to themselves, so we need to import from - // the top of the tree to the bottom to avoid foreign key conflicts. - // We do this by looping until we've imported them all, only importing if: - // - The parent has been imported - // - The environment hasn't already been imported - // The loop exits when imported.len == to_import.len - while imported_resources.environments.len() < resources.environments.len() { - for mut v in resources.environments.clone() { + let environments: Vec = resources + .environments + .into_iter() + .map(|mut v| { v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeEnvironment, &mut id_map); v.workspace_id = maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); v.environment_id = maybe_gen_id_opt(v.environment_id, ModelType::TypeEnvironment, &mut id_map); - if let Some(fid) = v.environment_id.clone() { - let imported_parent = imported_resources.environments.iter().find(|f| f.id == fid); - if imported_parent.is_none() { - continue; - } - } - if let Some(_) = imported_resources.environments.iter().find(|f| f.id == v.id) { - continue; - } - let x = upsert_environment(&window, v).await.map_err(|e| e.to_string())?; - imported_resources.environments.push(x.clone()); - } - } - info!("Imported {} environments", imported_resources.environments.len()); + v + }) + .collect(); - // Folders can foreign-key to themselves, so we need to import from - // the top of the tree to the bottom to avoid foreign key conflicts. - // We do this by looping until we've imported them all, only importing if: - // - The parent folder has been imported - // - The folder hasn't already been imported - // The loop exits when imported.len == to_import.len - while imported_resources.folders.len() < resources.folders.len() { - for mut v in resources.folders.clone() { + let folders: Vec = resources + .folders + .into_iter() + .map(|mut v| { v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeFolder, &mut id_map); v.workspace_id = maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map); - if let Some(fid) = v.folder_id.clone() { - let imported_parent = imported_resources.folders.iter().find(|f| f.id == fid); - if imported_parent.is_none() { - continue; - } - } - if let Some(_) = imported_resources.folders.iter().find(|f| f.id == v.id) { - continue; - } - let x = upsert_folder(&window, v).await.map_err(|e| e.to_string())?; - imported_resources.folders.push(x.clone()); - } - } - info!("Imported {} folders", imported_resources.folders.len()); + v + }) + .collect(); - for mut v in resources.http_requests { - v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeHttpRequest, &mut id_map); - v.workspace_id = - maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); - v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map); - let x = upsert_http_request(&window, v).await.map_err(|e| e.to_string())?; - imported_resources.http_requests.push(x.clone()); - } - info!("Imported {} http_requests", imported_resources.http_requests.len()); + let http_requests: Vec = resources + .http_requests + .into_iter() + .map(|mut v| { + v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeHttpRequest, &mut id_map); + v.workspace_id = + maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); + v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map); + v + }) + .collect(); - for mut v in resources.grpc_requests { - v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeGrpcRequest, &mut id_map); - v.workspace_id = - maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); - v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map); - let x = upsert_grpc_request(&window, v).await.map_err(|e| e.to_string())?; - imported_resources.grpc_requests.push(x.clone()); - } - info!("Imported {} grpc_requests", imported_resources.grpc_requests.len()); + let grpc_requests: Vec = resources + .grpc_requests + .into_iter() + .map(|mut v| { + v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeGrpcRequest, &mut id_map); + v.workspace_id = + maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map); + v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map); + v + }) + .collect(); + + let upserted = + batch_upsert(&window, workspaces, environments, folders, http_requests, grpc_requests) + .await + .map_err(|e| e.to_string())?; analytics::track_event( &window, @@ -938,7 +936,7 @@ async fn cmd_import_data( ) .await; - Ok(imported_resources) + Ok(upserted) } #[tauri::command] @@ -1000,7 +998,7 @@ async fn cmd_export_data( export_path: &str, workspace_ids: Vec<&str>, ) -> Result<(), String> { - let export_data = get_workspace_export_resources(&window, workspace_ids).await; + let export_data = get_workspace_export_resources(window.app_handle(), workspace_ids).await; let f = File::options() .create(true) .truncate(true) @@ -1049,8 +1047,9 @@ async fn cmd_send_http_request( // that has not yet been saved in the DB. request: HttpRequest, ) -> Result { - let response = - create_default_http_response(&window, &request.id).await.map_err(|e| e.to_string())?; + let response = create_default_http_response(&window, &request.id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string())?; let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false); window.listen_any(format!("cancel_http_response_{}", response.id), move |_event| { @@ -1087,7 +1086,9 @@ async fn response_err( let mut response = response.clone(); response.state = HttpResponseState::Closed; response.error = Some(error.clone()); - response = update_response_if_id(w, &response).await.expect("Failed to update response"); + response = update_response_if_id(w, &response, &UpdateSource::Window) + .await + .expect("Failed to update response"); response } @@ -1135,15 +1136,11 @@ async fn cmd_set_key_value( value: &str, w: WebviewWindow, ) -> Result { - let (key_value, _created) = set_key_value_raw(&w, namespace, key, value).await; + let (key_value, _created) = + set_key_value_raw(&w, namespace, key, value, &UpdateSource::Window).await; Ok(key_value) } -#[tauri::command] -async fn cmd_create_workspace(name: &str, w: WebviewWindow) -> Result { - upsert_workspace(&w, Workspace::new(name.to_string())).await.map_err(|e| e.to_string()) -} - #[tauri::command] async fn cmd_install_plugin( directory: &str, @@ -1163,6 +1160,7 @@ async fn cmd_install_plugin( url, ..Default::default() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string())?; @@ -1176,7 +1174,9 @@ async fn cmd_uninstall_plugin( plugin_manager: State<'_, PluginManager>, window: WebviewWindow, ) -> Result { - let plugin = delete_plugin(&window, plugin_id).await.map_err(|e| e.to_string())?; + let plugin = delete_plugin(&window, plugin_id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string())?; plugin_manager .uninstall(WindowContext::from_window(&window), plugin.directory.as_str()) @@ -1191,12 +1191,12 @@ async fn cmd_update_cookie_jar( cookie_jar: CookieJar, w: WebviewWindow, ) -> Result { - upsert_cookie_jar(&w, &cookie_jar).await.map_err(|e| e.to_string()) + upsert_cookie_jar(&w, &cookie_jar, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_delete_cookie_jar(w: WebviewWindow, cookie_jar_id: &str) -> Result { - delete_cookie_jar(&w, cookie_jar_id).await.map_err(|e| e.to_string()) + delete_cookie_jar(&w, cookie_jar_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1212,6 +1212,7 @@ async fn cmd_create_cookie_jar( workspace_id: workspace_id.to_string(), ..Default::default() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string()) @@ -1234,6 +1235,7 @@ async fn cmd_create_environment( variables, ..Default::default() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string()) @@ -1256,6 +1258,7 @@ async fn cmd_create_grpc_request( sort_priority, ..Default::default() }, + &UpdateSource::Window, ) .await .map_err(|e| e.to_string()) @@ -1263,7 +1266,7 @@ async fn cmd_create_grpc_request( #[tauri::command] async fn cmd_duplicate_grpc_request(id: &str, w: WebviewWindow) -> Result { - duplicate_grpc_request(&w, id).await.map_err(|e| e.to_string()) + duplicate_grpc_request(&w, id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1280,17 +1283,17 @@ async fn cmd_create_http_request( request: HttpRequest, w: WebviewWindow, ) -> Result { - upsert_http_request(&w, request).await.map_err(|e| e.to_string()) + upsert_http_request(&w, request, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_duplicate_http_request(id: &str, w: WebviewWindow) -> Result { - duplicate_http_request(&w, id).await.map_err(|e| e.to_string()) + duplicate_http_request(&w, id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_update_workspace(workspace: Workspace, w: WebviewWindow) -> Result { - upsert_workspace(&w, workspace).await.map_err(|e| e.to_string()) + upsert_workspace(&w, workspace, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1298,7 +1301,7 @@ async fn cmd_update_environment( environment: Environment, w: WebviewWindow, ) -> Result { - upsert_environment(&w, environment).await.map_err(|e| e.to_string()) + upsert_environment(&w, environment, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1306,7 +1309,7 @@ async fn cmd_update_grpc_request( request: GrpcRequest, w: WebviewWindow, ) -> Result { - upsert_grpc_request(&w, request).await.map_err(|e| e.to_string()) + upsert_grpc_request(&w, request, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1314,7 +1317,7 @@ async fn cmd_update_http_request( request: HttpRequest, window: WebviewWindow, ) -> Result { - upsert_http_request(&window, request).await.map_err(|e| e.to_string()) + upsert_http_request(&window, request, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1322,7 +1325,7 @@ async fn cmd_delete_grpc_request( w: WebviewWindow, request_id: &str, ) -> Result { - delete_grpc_request(&w, request_id).await.map_err(|e| e.to_string()) + delete_grpc_request(&w, request_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1330,7 +1333,7 @@ async fn cmd_delete_http_request( w: WebviewWindow, request_id: &str, ) -> Result { - delete_http_request(&w, request_id).await.map_err(|e| e.to_string()) + delete_http_request(&w, request_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1338,31 +1341,9 @@ async fn cmd_list_folders(workspace_id: &str, w: WebviewWindow) -> Result, - w: WebviewWindow, -) -> Result { - upsert_folder( - &w, - Folder { - workspace_id: workspace_id.to_string(), - name: name.to_string(), - folder_id: folder_id.map(|s| s.to_string()), - sort_priority, - ..Default::default() - }, - ) - .await - .map_err(|e| e.to_string()) -} - #[tauri::command] async fn cmd_update_folder(folder: Folder, w: WebviewWindow) -> Result { - upsert_folder(&w, folder).await.map_err(|e| e.to_string()) + upsert_folder(&w, folder, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1376,7 +1357,7 @@ async fn cmd_write_file_dev(pathname: &str, contents: &str) -> Result<(), String #[tauri::command] async fn cmd_delete_folder(w: WebviewWindow, folder_id: &str) -> Result { - delete_folder(&w, folder_id).await.map_err(|e| e.to_string()) + delete_folder(&w, folder_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1384,7 +1365,7 @@ async fn cmd_delete_environment( w: WebviewWindow, environment_id: &str, ) -> Result { - delete_environment(&w, environment_id).await.map_err(|e| e.to_string()) + delete_environment(&w, environment_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1424,6 +1405,9 @@ async fn cmd_list_environments( workspace_id: &str, w: WebviewWindow, ) -> Result, String> { + // Not sure of a better place to put this... + ensure_base_environment(&w, workspace_id).await.map_err(|e| e.to_string())?; + list_environments(&w, workspace_id).await.map_err(|e| e.to_string()) } @@ -1466,7 +1450,7 @@ async fn cmd_get_settings(w: WebviewWindow) -> Result { #[tauri::command] async fn cmd_update_settings(settings: Settings, w: WebviewWindow) -> Result { - update_settings(&w, settings).await.map_err(|e| e.to_string()) + update_settings(&w, settings, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1504,6 +1488,7 @@ async fn cmd_list_cookie_jars( workspace_id: workspace_id.to_string(), ..Default::default() }, + &UpdateSource::Window, ) .await .expect("Failed to create CookieJar"); @@ -1539,29 +1524,37 @@ async fn cmd_list_http_responses( #[tauri::command] async fn cmd_delete_http_response(id: &str, w: WebviewWindow) -> Result { - delete_http_response(&w, id).await.map_err(|e| e.to_string()) + delete_http_response(&w, id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_delete_grpc_connection(id: &str, w: WebviewWindow) -> Result { - delete_grpc_connection(&w, id).await.map_err(|e| e.to_string()) + delete_grpc_connection(&w, id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_delete_all_grpc_connections(request_id: &str, w: WebviewWindow) -> Result<(), String> { - delete_all_grpc_connections(&w, request_id).await.map_err(|e| e.to_string()) + delete_all_grpc_connections(&w, request_id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string()) } #[tauri::command] async fn cmd_delete_send_history(workspace_id: &str, w: WebviewWindow) -> Result<(), String> { - delete_all_http_responses_for_workspace(&w, workspace_id).await.map_err(|e| e.to_string())?; - delete_all_grpc_connections_for_workspace(&w, workspace_id).await.map_err(|e| e.to_string())?; + delete_all_http_responses_for_workspace(&w, workspace_id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string())?; + delete_all_grpc_connections_for_workspace(&w, workspace_id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] async fn cmd_delete_all_http_responses(request_id: &str, w: WebviewWindow) -> Result<(), String> { - delete_all_http_responses_for_request(&w, request_id).await.map_err(|e| e.to_string()) + delete_all_http_responses_for_request(&w, request_id, &UpdateSource::Window) + .await + .map_err(|e| e.to_string()) } #[tauri::command] @@ -1576,6 +1569,7 @@ async fn cmd_list_workspaces(w: WebviewWindow) -> Result, String> setting_validate_certificates: true, ..Default::default() }, + &UpdateSource::Window, ) .await .expect("Failed to create Workspace"); @@ -1662,7 +1656,7 @@ async fn cmd_new_main_window(app_handle: AppHandle, url: &str) -> Result<(), Str #[tauri::command] async fn cmd_delete_workspace(w: WebviewWindow, workspace_id: &str) -> Result { - delete_workspace(&w, workspace_id).await.map_err(|e| e.to_string()) + delete_workspace(&w, workspace_id, &UpdateSource::Window).await.map_err(|e| e.to_string()) } #[tauri::command] @@ -1724,9 +1718,10 @@ pub fn run() { .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) + .plugin(yaak_license::init()) .plugin(yaak_models::plugin::Builder::default().build()) - .plugin(tauri_plugin_yaak_license::init()) - .plugin(yaak_plugin_runtime::plugin::init()); + .plugin(yaak_plugins::init()) + .plugin(yaak_sync::init()); #[cfg(target_os = "macos")] { @@ -1759,10 +1754,8 @@ pub fn run() { cmd_check_for_updates, cmd_create_cookie_jar, cmd_create_environment, - cmd_create_folder, cmd_create_grpc_request, cmd_create_http_request, - cmd_create_workspace, cmd_curl_to_request, cmd_delete_all_grpc_connections, cmd_delete_all_http_responses, @@ -1897,7 +1890,16 @@ fn is_dev() -> bool { } fn create_main_window(handle: &AppHandle, url: &str) -> WebviewWindow { - let label = format!("{MAIN_WINDOW_PREFIX}{}", handle.webview_windows().len()); + let mut counter = 0; + let label = loop { + let label = format!("{MAIN_WINDOW_PREFIX}{counter}"); + match handle.webview_windows().get(label.as_str()) { + None => break Some(label), + Some(_) => counter += 1, + } + } + .expect("Failed to generate label for new window"); + let config = CreateWindowConfig { url, label: label.as_str(), @@ -2183,7 +2185,7 @@ async fn handle_plugin_event( updated_at: Utc::now().naive_utc(), // TODO: Add reloaded_at field to use instead ..plugin }; - upsert_plugin(&window, new_plugin).await.unwrap(); + upsert_plugin(&window, new_plugin, &UpdateSource::Plugin).await.unwrap(); } let toast_event = plugin_handle.build_event_to_send( WindowContext::from_window(&window), @@ -2203,8 +2205,13 @@ async fn handle_plugin_event( let cookie_jar = cookie_jar_from_window(&window).await; let environment = environment_from_window(&window).await; - let resp = - create_default_http_response(&window, req.http_request.id.as_str()).await.unwrap(); + let resp = create_default_http_response( + &window, + req.http_request.id.as_str(), + &UpdateSource::Plugin, + ) + .await + .unwrap(); let result = send_http_request( &window, diff --git a/src-tauri/src/notifications.rs b/src-tauri/src/notifications.rs index 8848e53d..abaed170 100644 --- a/src-tauri/src/notifications.rs +++ b/src-tauri/src/notifications.rs @@ -6,7 +6,7 @@ use log::debug; use reqwest::Method; use serde::{Deserialize, Serialize}; use tauri::{Emitter, Manager, Runtime, WebviewWindow}; -use yaak_models::queries::{get_key_value_raw, set_key_value_raw}; +use yaak_models::queries::{get_key_value_raw, set_key_value_raw, UpdateSource}; // Check for updates every hour const MAX_UPDATE_CHECK_SECONDS: u64 = 60 * 60; @@ -47,7 +47,7 @@ impl YaakNotifier { seen.push(id.to_string()); debug!("Marked notification as seen {}", id); let seen_json = serde_json::to_string(&seen).map_err(|e| e.to_string())?; - set_key_value_raw(w, KV_NAMESPACE, KV_KEY, seen_json.as_str()).await; + set_key_value_raw(w, KV_NAMESPACE, KV_KEY, seen_json.as_str(), &UpdateSource::Window).await; Ok(()) } diff --git a/src-tauri/src/template_callback.rs b/src-tauri/src/template_callback.rs index d7cd3e48..01dffacf 100644 --- a/src-tauri/src/template_callback.rs +++ b/src-tauri/src/template_callback.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use tauri::{AppHandle, Manager, Runtime}; -use yaak_plugin_runtime::events::{RenderPurpose, TemplateFunctionArg, WindowContext}; -use yaak_plugin_runtime::manager::PluginManager; +use yaak_plugins::events::{RenderPurpose, TemplateFunctionArg, WindowContext}; +use yaak_plugins::manager::PluginManager; use yaak_templates::TemplateCallback; #[derive(Clone)] diff --git a/src-tauri/src/updates.rs b/src-tauri/src/updates.rs index 6d7cb7f0..968b1479 100644 --- a/src-tauri/src/updates.rs +++ b/src-tauri/src/updates.rs @@ -6,7 +6,7 @@ use tauri::{AppHandle, Manager}; use tauri_plugin_dialog::{DialogExt, MessageDialogButtons}; use tauri_plugin_updater::UpdaterExt; use tokio::task::block_in_place; -use yaak_plugin_runtime::manager::PluginManager; +use yaak_plugins::manager::PluginManager; use crate::is_dev; diff --git a/src-tauri/yaak_grpc/Cargo.toml b/src-tauri/yaak-grpc/Cargo.toml similarity index 97% rename from src-tauri/yaak_grpc/Cargo.toml rename to src-tauri/yaak-grpc/Cargo.toml index 816db0fd..a99c1e03 100644 --- a/src-tauri/yaak_grpc/Cargo.toml +++ b/src-tauri/yaak-grpc/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "yaak_grpc" +name = "yaak-grpc" version = "0.1.0" edition = "2021" publish = false diff --git a/src-tauri/yaak_grpc/src/codec.rs b/src-tauri/yaak-grpc/src/codec.rs similarity index 100% rename from src-tauri/yaak_grpc/src/codec.rs rename to src-tauri/yaak-grpc/src/codec.rs diff --git a/src-tauri/yaak_grpc/src/json_schema.rs b/src-tauri/yaak-grpc/src/json_schema.rs similarity index 100% rename from src-tauri/yaak_grpc/src/json_schema.rs rename to src-tauri/yaak-grpc/src/json_schema.rs diff --git a/src-tauri/yaak_grpc/src/lib.rs b/src-tauri/yaak-grpc/src/lib.rs similarity index 100% rename from src-tauri/yaak_grpc/src/lib.rs rename to src-tauri/yaak-grpc/src/lib.rs diff --git a/src-tauri/yaak_grpc/src/manager.rs b/src-tauri/yaak-grpc/src/manager.rs similarity index 100% rename from src-tauri/yaak_grpc/src/manager.rs rename to src-tauri/yaak-grpc/src/manager.rs diff --git a/src-tauri/yaak_grpc/src/proto.rs b/src-tauri/yaak-grpc/src/proto.rs similarity index 100% rename from src-tauri/yaak_grpc/src/proto.rs rename to src-tauri/yaak-grpc/src/proto.rs diff --git a/src-tauri/yaak_license/Cargo.toml b/src-tauri/yaak-license/Cargo.toml similarity index 79% rename from src-tauri/yaak_license/Cargo.toml rename to src-tauri/yaak-license/Cargo.toml index dcab32a3..332a4d5e 100644 --- a/src-tauri/yaak_license/Cargo.toml +++ b/src-tauri/yaak-license/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "tauri-plugin-yaak-license" -links = "tauri-plugin-yaak-license" +name = "yaak-license" +links = "yaak-license" version = "0.1.0" edition = "2021" publish = false @@ -11,7 +11,7 @@ serde = { version = "1.0.208", features = ["derive"] } ts-rs = { workspace = true } thiserror = { workspace = true } tauri = { workspace = true } -yaak_models = { workspace = true } +yaak-models = { workspace = true } chrono = "0.4.38" log = "0.4.22" serde_json = "1.0.132" diff --git a/src-tauri/yaak_license/bindings/license.ts b/src-tauri/yaak-license/bindings/license.ts similarity index 100% rename from src-tauri/yaak_license/bindings/license.ts rename to src-tauri/yaak-license/bindings/license.ts diff --git a/src-tauri/yaak_license/bindings/models.ts b/src-tauri/yaak-license/bindings/models.ts similarity index 100% rename from src-tauri/yaak_license/bindings/models.ts rename to src-tauri/yaak-license/bindings/models.ts diff --git a/src-tauri/yaak_license/build.rs b/src-tauri/yaak-license/build.rs similarity index 100% rename from src-tauri/yaak_license/build.rs rename to src-tauri/yaak-license/build.rs diff --git a/src-tauri/yaak_license/index.ts b/src-tauri/yaak-license/index.ts similarity index 69% rename from src-tauri/yaak_license/index.ts rename to src-tauri/yaak-license/index.ts index f99f5f9c..aedf27c6 100644 --- a/src-tauri/yaak_license/index.ts +++ b/src-tauri/yaak-license/index.ts @@ -1,6 +1,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { invoke } from '@tauri-apps/api/core'; -import { useListenToTauriEvent } from '@yaakapp/app/hooks/useListenToTauriEvent'; +import { listen } from '@tauri-apps/api/event'; +import { useEffect } from 'react'; import { LicenseCheckStatus } from './bindings/license'; export * from './bindings/license'; @@ -10,15 +11,15 @@ export function useLicense() { const activate = useMutation({ mutationKey: ['license.activate'], mutationFn: (payload) => invoke('plugin:yaak-license|activate', payload), - onSuccess: async () => { - await queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }); - }, + onSuccess: () => queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }), }); // Check the license again after a license is activated - useListenToTauriEvent('license-activated', async () => { - await queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }); - }); + useEffect(() => { + listen('license-activated', () => { + queryClient.invalidateQueries({ queryKey: CHECK_QUERY_KEY }).catch(console.error); + }).then(console.error); + }, []); const CHECK_QUERY_KEY = ['license.check']; const check = useQuery({ diff --git a/src-tauri/yaak_license/package.json b/src-tauri/yaak-license/package.json similarity index 100% rename from src-tauri/yaak_license/package.json rename to src-tauri/yaak-license/package.json diff --git a/src-tauri/yaak_license/permissions/autogenerated/commands/activate.toml b/src-tauri/yaak-license/permissions/autogenerated/commands/activate.toml similarity index 100% rename from src-tauri/yaak_license/permissions/autogenerated/commands/activate.toml rename to src-tauri/yaak-license/permissions/autogenerated/commands/activate.toml diff --git a/src-tauri/yaak_license/permissions/autogenerated/commands/check.toml b/src-tauri/yaak-license/permissions/autogenerated/commands/check.toml similarity index 100% rename from src-tauri/yaak_license/permissions/autogenerated/commands/check.toml rename to src-tauri/yaak-license/permissions/autogenerated/commands/check.toml diff --git a/src-tauri/yaak_license/permissions/autogenerated/reference.md b/src-tauri/yaak-license/permissions/autogenerated/reference.md similarity index 100% rename from src-tauri/yaak_license/permissions/autogenerated/reference.md rename to src-tauri/yaak-license/permissions/autogenerated/reference.md diff --git a/src-tauri/yaak_license/permissions/default.toml b/src-tauri/yaak-license/permissions/default.toml similarity index 100% rename from src-tauri/yaak_license/permissions/default.toml rename to src-tauri/yaak-license/permissions/default.toml diff --git a/src-tauri/yaak_license/permissions/schemas/schema.json b/src-tauri/yaak-license/permissions/schemas/schema.json similarity index 100% rename from src-tauri/yaak_license/permissions/schemas/schema.json rename to src-tauri/yaak-license/permissions/schemas/schema.json diff --git a/src-tauri/yaak_license/src/commands.rs b/src-tauri/yaak-license/src/commands.rs similarity index 100% rename from src-tauri/yaak_license/src/commands.rs rename to src-tauri/yaak-license/src/commands.rs diff --git a/src-tauri/yaak_license/src/errors.rs b/src-tauri/yaak-license/src/errors.rs similarity index 100% rename from src-tauri/yaak_license/src/errors.rs rename to src-tauri/yaak-license/src/errors.rs diff --git a/src-tauri/yaak_license/src/lib.rs b/src-tauri/yaak-license/src/lib.rs similarity index 100% rename from src-tauri/yaak_license/src/lib.rs rename to src-tauri/yaak-license/src/lib.rs diff --git a/src-tauri/yaak_license/src/license.rs b/src-tauri/yaak-license/src/license.rs similarity index 98% rename from src-tauri/yaak_license/src/license.rs rename to src-tauri/yaak-license/src/license.rs index 4453ad44..fd0bebf6 100644 --- a/src-tauri/yaak_license/src/license.rs +++ b/src-tauri/yaak-license/src/license.rs @@ -7,6 +7,7 @@ use std::ops::Add; use std::time::Duration; use tauri::{is_dev, AppHandle, Emitter, Runtime, WebviewWindow}; use ts_rs::TS; +use yaak_models::queries::UpdateSource; const KV_NAMESPACE: &str = "license"; const KV_ACTIVATION_ID_KEY: &str = "activation_id"; @@ -75,6 +76,7 @@ pub async fn activate_license( KV_ACTIVATION_ID_KEY, KV_NAMESPACE, body.activation_id.as_str(), + &UpdateSource::Window, ) .await; diff --git a/src-tauri/yaak_models/Cargo.toml b/src-tauri/yaak-models/Cargo.toml similarity index 63% rename from src-tauri/yaak_models/Cargo.toml rename to src-tauri/yaak-models/Cargo.toml index 734014c8..87b7848e 100644 --- a/src-tauri/yaak_models/Cargo.toml +++ b/src-tauri/yaak-models/Cargo.toml @@ -1,21 +1,21 @@ [package] -name = "yaak_models" +name = "yaak-models" version = "0.1.0" edition = "2021" publish = false [dependencies] chrono = { version = "0.4.38", features = ["serde"] } -rusqlite = { version = "0.31.0", features = ["bundled", "chrono"] } -sea-query = { version = "0.31.0", features = ["with-chrono", "attr"] } -sea-query-rusqlite = { version = "0.6.0", features = ["with-chrono"] } +log = "0.4.22" +nanoid = "0.4.0" +r2d2 = "0.8.10" +r2d2_sqlite = { version = "0.25.0" } +rusqlite = { version = "0.32.1", features = ["bundled", "chrono"] } +sea-query = { version = "0.32.1", features = ["with-chrono", "attr"] } +sea-query-rusqlite = { version = "0.7.0", features = ["with-chrono"] } serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.122" +sqlx = { version = "0.8.0", features = ["sqlite", "runtime-tokio-rustls"] } +tauri = { workspace = true } thiserror = "1.0.63" ts-rs = { workspace = true, features = ["chrono-impl", "serde-json-impl"] } -tauri = { workspace = true } -sqlx = { version = "0.8.0", features = ["sqlite", "runtime-tokio-rustls"] } -log = "0.4.22" -rand = "0.8.5" -r2d2 = "0.8.10" -r2d2_sqlite = { version = "0.24.0" } diff --git a/src-tauri/yaak_models/bindings/models.ts b/src-tauri/yaak-models/bindings/models.ts similarity index 91% rename from src-tauri/yaak_models/bindings/models.ts rename to src-tauri/yaak-models/bindings/models.ts index 3aad7c90..ca75982f 100644 --- a/src-tauri/yaak_models/bindings/models.ts +++ b/src-tauri/yaak-models/bindings/models.ts @@ -42,6 +42,8 @@ export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, export type KeyValue = { model: "key_value", createdAt: string, updatedAt: string, key: string, namespace: string, value: string, }; +export type ModelPayload = { model: AnyModel, windowLabel: string, updateSource: UpdateSource, }; + export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, }; export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, } | { "type": "disabled" }; @@ -50,4 +52,8 @@ export type ProxySettingAuth = { user: string, password: string, }; export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, telemetry: boolean, theme: string, themeDark: string, themeLight: string, updateChannel: string, proxy: ProxySetting | null, }; -export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, }; +export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, }; + +export type UpdateSource = "sync" | "window" | "plugin" | "background"; + +export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, settingSyncDir: string | null, }; diff --git a/src-tauri/yaak_models/index.ts b/src-tauri/yaak-models/index.ts similarity index 100% rename from src-tauri/yaak_models/index.ts rename to src-tauri/yaak-models/index.ts diff --git a/src-tauri/yaak_models/package.json b/src-tauri/yaak-models/package.json similarity index 100% rename from src-tauri/yaak_models/package.json rename to src-tauri/yaak-models/package.json diff --git a/src-tauri/yaak_models/src/error.rs b/src-tauri/yaak-models/src/error.rs similarity index 100% rename from src-tauri/yaak_models/src/error.rs rename to src-tauri/yaak-models/src/error.rs diff --git a/src-tauri/yaak_models/src/lib.rs b/src-tauri/yaak-models/src/lib.rs similarity index 53% rename from src-tauri/yaak_models/src/lib.rs rename to src-tauri/yaak-models/src/lib.rs index d6b3e6cd..23512ac1 100644 --- a/src-tauri/yaak_models/src/lib.rs +++ b/src-tauri/yaak-models/src/lib.rs @@ -1,5 +1,5 @@ pub mod models; pub mod queries; -mod error; +pub mod error; pub mod plugin; \ No newline at end of file diff --git a/src-tauri/yaak_models/src/models.rs b/src-tauri/yaak-models/src/models.rs similarity index 87% rename from src-tauri/yaak_models/src/models.rs rename to src-tauri/yaak-models/src/models.rs index 00db714b..b92ea709 100644 --- a/src-tauri/yaak_models/src/models.rs +++ b/src-tauri/yaak-models/src/models.rs @@ -1,7 +1,7 @@ use chrono::NaiveDateTime; use rusqlite::Row; use sea_query::Iden; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use serde_json::Value; use std::collections::BTreeMap; use ts_rs::TS; @@ -117,6 +117,7 @@ pub struct Workspace { #[serde(default = "default_true")] pub setting_follow_redirects: bool, pub setting_request_timeout: i32, + pub setting_sync_dir: Option, } #[derive(Iden)] @@ -132,6 +133,7 @@ pub enum WorkspaceIden { Name, SettingFollowRedirects, SettingRequestTimeout, + SettingSyncDir, SettingValidateCertificates, } @@ -146,9 +148,10 @@ impl<'s> TryFrom<&Row<'s>> for Workspace { updated_at: r.get("updated_at")?, name: r.get("name")?, description: r.get("description")?, - setting_validate_certificates: r.get("setting_validate_certificates")?, setting_follow_redirects: r.get("setting_follow_redirects")?, setting_request_timeout: r.get("setting_request_timeout")?, + setting_sync_dir: r.get("setting_sync_dir")?, + setting_validate_certificates: r.get("setting_validate_certificates")?, }) } } @@ -864,6 +867,60 @@ impl<'s> TryFrom<&Row<'s>> for Plugin { } } +#[derive(Debug, Clone, Serialize, Deserialize, Default, TS)] +#[serde(default, rename_all = "camelCase")] +#[ts(export, export_to = "models.ts")] +pub struct SyncState { + #[ts(type = "\"sync_state\"")] + pub model: String, + pub id: String, + pub workspace_id: String, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, + pub flushed_at: NaiveDateTime, + + pub model_id: String, + pub checksum: String, + pub rel_path: String, + pub sync_dir: String, +} + +#[derive(Iden)] +pub enum SyncStateIden { + #[iden = "sync_states"] + Table, + Model, + Id, + WorkspaceId, + CreatedAt, + UpdatedAt, + + Checksum, + FlushedAt, + ModelId, + RelPath, + SyncDir, +} + +impl<'s> TryFrom<&Row<'s>> for SyncState { + type Error = rusqlite::Error; + + fn try_from(r: &Row<'s>) -> Result { + Ok(SyncState { + id: r.get("id")?, + workspace_id: r.get("workspace_id")?, + model: r.get("model")?, + created_at: r.get("created_at")?, + updated_at: r.get("updated_at")?, + flushed_at: r.get("flushed_at")?, + checksum: r.get("checksum")?, + model_id: r.get("model_id")?, + sync_dir: r.get("sync_dir")?, + rel_path: r.get("rel_path")?, + }) + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Default, TS)] #[serde(default, rename_all = "camelCase")] #[ts(export, export_to = "models.ts")] @@ -925,6 +982,7 @@ pub enum ModelType { TypeHttpResponse, TypePlugin, TypeWorkspace, + TypeSyncState, } impl ModelType { @@ -940,12 +998,13 @@ impl ModelType { ModelType::TypeHttpResponse => "rs", ModelType::TypePlugin => "pg", ModelType::TypeWorkspace => "wk", + ModelType::TypeSyncState => "ss", } .to_string() } } -#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Serialize, TS)] #[serde(rename_all = "camelCase", untagged)] #[ts(export, export_to = "models.ts")] pub enum AnyModel { @@ -962,3 +1021,54 @@ pub enum AnyModel { KeyValue(KeyValue), Workspace(Workspace), } + +impl<'de> Deserialize<'de> for AnyModel { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = Value::deserialize(deserializer)?; + let model = value.as_object().unwrap(); + + let model = match model.get("model") { + Some(m) if m == "http_request" => { + AnyModel::HttpRequest(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "grpc_request" => { + AnyModel::GrpcRequest(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "workspace" => { + AnyModel::Workspace(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "environment" => { + AnyModel::Environment(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "folder" => { + AnyModel::Folder(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "key_value" => { + AnyModel::KeyValue(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "grpc_connection" => { + AnyModel::GrpcConnection(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "grpc_event" => { + AnyModel::GrpcEvent(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "cookie_jar" => { + AnyModel::CookieJar(serde_json::from_value(value).unwrap()) + } + Some(m) if m == "plugin" => { + AnyModel::Plugin(serde_json::from_value(value).unwrap()) + } + Some(m) => { + return Err(serde::de::Error::custom(format!("Unknown model {}", m))); + } + None => { + return Err(serde::de::Error::custom("Missing or invalid model")); + } + }; + + Ok(model) + } +} diff --git a/src-tauri/yaak_models/src/plugin.rs b/src-tauri/yaak-models/src/plugin.rs similarity index 78% rename from src-tauri/yaak_models/src/plugin.rs rename to src-tauri/yaak-models/src/plugin.rs index e95a7d6a..072cc2f9 100644 --- a/src-tauri/yaak_models/src/plugin.rs +++ b/src-tauri/yaak-models/src/plugin.rs @@ -4,15 +4,14 @@ use r2d2_sqlite::SqliteConnectionManager; use serde::Deserialize; use sqlx::migrate::Migrator; use sqlx::sqlite::SqliteConnectOptions; -use sqlx::SqlitePool; -use std::fs::{create_dir_all, File}; +use sqlx::{ConnectOptions, SqlitePool}; +use std::fs::create_dir_all; use std::path::PathBuf; -use std::str::FromStr; use std::time::Duration; use tauri::async_runtime::Mutex; use tauri::path::BaseDirectory; use tauri::plugin::TauriPlugin; -use tauri::{plugin, AppHandle, Manager, Runtime}; +use tauri::{plugin, AppHandle, Manager, Runtime, Url}; pub struct SqliteConnection(pub Mutex>); @@ -62,25 +61,17 @@ impl Builder { } } -async fn must_migrate_db(app_handle: &AppHandle, path: &PathBuf) { - let app_data_dir = app_handle.path().app_data_dir().unwrap(); - let sqlite_file_path = app_data_dir.join("db.sqlite"); - - info!("Creating database file at {:?}", sqlite_file_path); - File::options() - .write(true) - .create(true) - .open(&sqlite_file_path) - .expect("Problem creating database file!"); - +fn db_connection_url(sqlite_file_path: &PathBuf) -> Url { let p_string = sqlite_file_path.to_string_lossy().replace(' ', "%20"); let url = format!("sqlite://{}?mode=rwc", p_string); + Url::parse(&url).unwrap() +} +async fn must_migrate_db(app_handle: &AppHandle, sqlite_file_path: &PathBuf) { + let url = db_connection_url(sqlite_file_path); info!("Connecting to database at {}", url); - let opts = SqliteConnectOptions::from_str(path.to_string_lossy().to_string().as_str()).unwrap(); - let pool = SqlitePool::connect_with(opts) - .await - .expect("Failed to connect to database"); + let opts = SqliteConnectOptions::from_url(&url).unwrap(); + let pool = SqlitePool::connect_with(opts).await.expect("Failed to connect to database"); let p = app_handle .path() .resolve("migrations", BaseDirectory::Resource) diff --git a/src-tauri/yaak_models/src/queries.rs b/src-tauri/yaak-models/src/queries.rs similarity index 75% rename from src-tauri/yaak_models/src/queries.rs rename to src-tauri/yaak-models/src/queries.rs index fe993d4f..155ad894 100644 --- a/src-tauri/yaak_models/src/queries.rs +++ b/src-tauri/yaak-models/src/queries.rs @@ -1,24 +1,26 @@ -use std::fs; - use crate::error::Error::ModelNotFound; use crate::error::Result; use crate::models::{ - CookieJar, CookieJarIden, Environment, EnvironmentIden, Folder, FolderIden, GrpcConnection, - GrpcConnectionIden, GrpcConnectionState, GrpcEvent, GrpcEventIden, GrpcRequest, + AnyModel, CookieJar, CookieJarIden, Environment, EnvironmentIden, Folder, FolderIden, + GrpcConnection, GrpcConnectionIden, GrpcConnectionState, GrpcEvent, GrpcEventIden, GrpcRequest, GrpcRequestIden, HttpRequest, HttpRequestIden, HttpResponse, HttpResponseHeader, HttpResponseIden, HttpResponseState, KeyValue, KeyValueIden, ModelType, Plugin, PluginIden, - Settings, SettingsIden, Workspace, WorkspaceIden, + Settings, SettingsIden, SyncState, SyncStateIden, Workspace, WorkspaceIden, }; use crate::plugin::SqliteConnection; -use log::{debug, error, info}; -use rand::distributions::{Alphanumeric, DistString}; +use chrono::NaiveDateTime; +use log::{debug, error, info, warn}; +use nanoid::nanoid; use rusqlite::OptionalExtension; use sea_query::ColumnRef::Asterisk; use sea_query::Keyword::CurrentTimestamp; use sea_query::{Cond, Expr, OnConflict, Order, Query, SqliteQueryBuilder}; use sea_query_rusqlite::RusqliteBinder; -use serde::Serialize; -use tauri::{AppHandle, Emitter, Manager, Runtime, WebviewWindow}; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::PathBuf; +use tauri::{AppHandle, Emitter, Listener, Manager, Runtime, WebviewWindow}; +use ts_rs::TS; const MAX_GRPC_CONNECTIONS_PER_REQUEST: usize = 20; const MAX_HTTP_RESPONSES_PER_REQUEST: usize = MAX_GRPC_CONNECTIONS_PER_REQUEST; @@ -28,9 +30,10 @@ pub async fn set_key_value_string( namespace: &str, key: &str, value: &str, + update_source: &UpdateSource, ) -> (KeyValue, bool) { let encoded = serde_json::to_string(value); - set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await + set_key_value_raw(mgr, namespace, key, &encoded.unwrap(), update_source).await } pub async fn set_key_value_int( @@ -38,9 +41,10 @@ pub async fn set_key_value_int( namespace: &str, key: &str, value: i32, + update_source: &UpdateSource, ) -> (KeyValue, bool) { let encoded = serde_json::to_string(&value); - set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await + set_key_value_raw(mgr, namespace, key, &encoded.unwrap(), update_source).await } pub async fn get_key_value_string( @@ -90,6 +94,7 @@ pub async fn set_key_value_raw( namespace: &str, key: &str, value: &str, + update_source: &UpdateSource, ) -> (KeyValue, bool) { let existing = get_key_value_raw(w, namespace, key).await; @@ -120,10 +125,11 @@ pub async fn set_key_value_raw( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str()).expect("Failed to prepare KeyValue upsert"); - let kv = stmt + let m: KeyValue = stmt .query_row(&*params.as_params(), |row| row.try_into()) .expect("Failed to upsert KeyValue"); - (emit_upserted_model(w, kv), existing.is_none()) + emit_upserted_model(w, &AnyModel::KeyValue(m.to_owned()), update_source); + (m, existing.is_none()) } pub async fn list_key_values_raw(mgr: &impl Manager) -> Result> { @@ -186,6 +192,7 @@ pub async fn get_workspace(mgr: &impl Manager, id: &str) -> Resul pub async fn upsert_workspace( window: &WebviewWindow, workspace: Workspace, + update_source: &UpdateSource, ) -> Result { let id = match workspace.id.as_str() { "" => generate_model_id(ModelType::TypeWorkspace), @@ -193,54 +200,63 @@ pub async fn upsert_workspace( }; let trimmed_name = workspace.name.trim(); - let dbm = &*window.app_handle().state::(); - let db = dbm.0.lock().await.get().unwrap(); + let m: Workspace = { + let dbm = &*window.app_handle().state::(); + let db = dbm.0.lock().await.get().unwrap(); - let (sql, params) = Query::insert() - .into_table(WorkspaceIden::Table) - .columns([ - WorkspaceIden::Id, - WorkspaceIden::CreatedAt, - WorkspaceIden::UpdatedAt, - WorkspaceIden::Name, - WorkspaceIden::Description, - WorkspaceIden::SettingRequestTimeout, - WorkspaceIden::SettingFollowRedirects, - WorkspaceIden::SettingValidateCertificates, - ]) - .values_panic([ - id.as_str().into(), - CurrentTimestamp.into(), - CurrentTimestamp.into(), - trimmed_name.into(), - workspace.description.into(), - workspace.setting_request_timeout.into(), - workspace.setting_follow_redirects.into(), - workspace.setting_validate_certificates.into(), - ]) - .on_conflict( - OnConflict::column(GrpcRequestIden::Id) - .update_columns([ - WorkspaceIden::UpdatedAt, - WorkspaceIden::Name, - WorkspaceIden::Description, - WorkspaceIden::SettingRequestTimeout, - WorkspaceIden::SettingFollowRedirects, - WorkspaceIden::SettingValidateCertificates, - ]) - .to_owned(), - ) - .returning_all() - .build_rusqlite(SqliteQueryBuilder); + let (sql, params) = Query::insert() + .into_table(WorkspaceIden::Table) + .columns([ + WorkspaceIden::Id, + WorkspaceIden::CreatedAt, + WorkspaceIden::UpdatedAt, + WorkspaceIden::Name, + WorkspaceIden::Description, + WorkspaceIden::SettingFollowRedirects, + WorkspaceIden::SettingRequestTimeout, + WorkspaceIden::SettingSyncDir, + WorkspaceIden::SettingValidateCertificates, + ]) + .values_panic([ + id.as_str().into(), + CurrentTimestamp.into(), + CurrentTimestamp.into(), + trimmed_name.into(), + workspace.description.into(), + workspace.setting_follow_redirects.into(), + workspace.setting_request_timeout.into(), + workspace.setting_sync_dir.into(), + workspace.setting_validate_certificates.into(), + ]) + .on_conflict( + OnConflict::column(GrpcRequestIden::Id) + .update_columns([ + WorkspaceIden::UpdatedAt, + WorkspaceIden::Name, + WorkspaceIden::Description, + WorkspaceIden::SettingRequestTimeout, + WorkspaceIden::SettingFollowRedirects, + WorkspaceIden::SettingRequestTimeout, + WorkspaceIden::SettingSyncDir, + WorkspaceIden::SettingValidateCertificates, + ]) + .to_owned(), + ) + .returning_all() + .build_rusqlite(SqliteQueryBuilder); - let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let mut stmt = db.prepare(&sql)?; + stmt.query_row(&*params.as_params(), |row| row.try_into())? + }; + emit_upserted_model(window, &AnyModel::Workspace(m.to_owned()), update_source); + ensure_base_environment(window, &m.id).await?; + Ok(m) } pub async fn delete_workspace( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let workspace = get_workspace(window, id).await?; @@ -254,10 +270,11 @@ pub async fn delete_workspace( db.execute(sql.as_str(), &*params.as_params())?; for r in list_responses_by_workspace_id(window, id).await? { - delete_http_response(window, &r.id).await?; + delete_http_response(window, &r.id, update_source).await?; } - emit_deleted_model(window, workspace) + emit_deleted_model(window, &AnyModel::Workspace(workspace.to_owned()), update_source); + Ok(workspace) } pub async fn get_cookie_jar(mgr: &impl Manager, id: &str) -> Result { @@ -292,6 +309,7 @@ pub async fn list_cookie_jars( pub async fn delete_cookie_jar( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let cookie_jar = get_cookie_jar(window, id).await?; let dbm = &*window.app_handle().state::(); @@ -303,12 +321,14 @@ pub async fn delete_cookie_jar( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, cookie_jar) + emit_deleted_model(window, &AnyModel::CookieJar(cookie_jar.to_owned()), update_source); + Ok(cookie_jar) } pub async fn duplicate_grpc_request( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let mut request = match get_grpc_request(window, id).await? { Some(r) => r, @@ -318,14 +338,15 @@ pub async fn duplicate_grpc_request( }; request.sort_priority = request.sort_priority + 0.001; request.id = "".to_string(); - upsert_grpc_request(window, request).await + upsert_grpc_request(window, request, update_source).await } pub async fn delete_grpc_request( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { - let req = match get_grpc_request(window, id).await? { + let grpc_request = match get_grpc_request(window, id).await? { Some(r) => r, None => { return Err(ModelNotFound(id.to_string())); @@ -340,12 +361,14 @@ pub async fn delete_grpc_request( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, req) + emit_deleted_model(window, &AnyModel::GrpcRequest(grpc_request.to_owned()), update_source); + Ok(grpc_request) } pub async fn upsert_grpc_request( window: &WebviewWindow, request: GrpcRequest, + update_source: &UpdateSource, ) -> Result { let id = match request.id.as_str() { "" => generate_model_id(ModelType::TypeGrpcRequest), @@ -414,8 +437,9 @@ pub async fn upsert_grpc_request( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: GrpcRequest = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::GrpcRequest(m.to_owned()), update_source); + Ok(m) } pub async fn get_grpc_request( @@ -453,12 +477,13 @@ pub async fn list_grpc_requests( pub async fn upsert_grpc_connection( window: &WebviewWindow, connection: &GrpcConnection, + update_source: &UpdateSource, ) -> Result { let connections = list_http_responses_for_request(window, connection.request_id.as_str(), None).await?; for c in connections.iter().skip(MAX_GRPC_CONNECTIONS_PER_REQUEST - 1) { debug!("Deleting old grpc connection {}", c.id); - delete_grpc_connection(window, c.id.as_str()).await?; + delete_grpc_connection(window, c.id.as_str(), update_source).await?; } let id = match connection.id.as_str() { @@ -518,8 +543,9 @@ pub async fn upsert_grpc_connection( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: GrpcConnection = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::GrpcConnection(m.to_owned()), update_source); + Ok(m) } pub async fn get_grpc_connection( @@ -576,8 +602,9 @@ pub async fn list_grpc_connections_for_request( pub async fn delete_grpc_connection( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { - let resp = get_grpc_connection(window, id).await?; + let m = get_grpc_connection(window, id).await?; let dbm = &*window.app_handle().state::(); let db = dbm.0.lock().await.get().unwrap(); @@ -588,15 +615,17 @@ pub async fn delete_grpc_connection( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, resp) + emit_deleted_model(window, &AnyModel::GrpcConnection(m.to_owned()), update_source); + Ok(m) } pub async fn delete_all_grpc_connections( window: &WebviewWindow, request_id: &str, + update_source: &UpdateSource, ) -> Result<()> { for r in list_grpc_connections_for_request(window, request_id).await? { - delete_grpc_connection(window, &r.id).await?; + delete_grpc_connection(window, &r.id, update_source).await?; } Ok(()) } @@ -604,9 +633,10 @@ pub async fn delete_all_grpc_connections( pub async fn delete_all_grpc_connections_for_workspace( window: &WebviewWindow, workspace_id: &str, + update_source: &UpdateSource, ) -> Result<()> { for r in list_grpc_connections_for_workspace(window, workspace_id).await? { - delete_grpc_connection(window, &r.id).await?; + delete_grpc_connection(window, &r.id, update_source).await?; } Ok(()) } @@ -614,6 +644,7 @@ pub async fn delete_all_grpc_connections_for_workspace( pub async fn upsert_grpc_event( window: &WebviewWindow, event: &GrpcEvent, + update_source: &UpdateSource, ) -> Result { let id = match event.id.as_str() { "" => generate_model_id(ModelType::TypeGrpcEvent), @@ -666,8 +697,9 @@ pub async fn upsert_grpc_event( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: GrpcEvent = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::GrpcEvent(m.to_owned()), update_source); + Ok(m) } pub async fn get_grpc_event(mgr: &impl Manager, id: &str) -> Result { @@ -703,6 +735,7 @@ pub async fn list_grpc_events( pub async fn upsert_cookie_jar( window: &WebviewWindow, cookie_jar: &CookieJar, + update_source: &UpdateSource, ) -> Result { let id = match cookie_jar.id.as_str() { "" => generate_model_id(ModelType::TypeCookieJar), @@ -744,16 +777,42 @@ pub async fn upsert_cookie_jar( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: CookieJar = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::CookieJar(m.to_owned()), update_source); + Ok(m) +} + +pub async fn ensure_base_environment( + window: &WebviewWindow, + workspace_id: &str, +) -> Result<()> { + let environments = list_environments(window, workspace_id).await?; + let base_environment = + environments.iter().find(|e| e.environment_id == None && e.workspace_id == workspace_id); + + if let None = base_environment { + info!("Creating base environment for {workspace_id}"); + upsert_environment( + window, + Environment { + workspace_id: workspace_id.to_string(), + name: "Global Variables".to_string(), + ..Default::default() + }, + &UpdateSource::Background, + ) + .await?; + } + + Ok(()) } pub async fn list_environments( - window: &WebviewWindow, + mgr: &impl Manager, workspace_id: &str, ) -> Result> { - let mut environments: Vec = { - let dbm = &*window.state::(); + let environments: Vec = { + let dbm = &*mgr.state::(); let db = dbm.0.lock().await.get().unwrap(); let (sql, params) = Query::select() .from(EnvironmentIden::Table) @@ -766,29 +825,13 @@ pub async fn list_environments( items.map(|v| v.unwrap()).collect() }; - let base_environment = - environments.iter().find(|e| e.environment_id == None && e.workspace_id == workspace_id); - - if let None = base_environment { - info!("Creating base environment for {workspace_id}"); - let base_environment = upsert_environment( - window, - Environment { - workspace_id: workspace_id.to_string(), - name: "Global Variables".to_string(), - ..Default::default() - }, - ) - .await?; - environments.push(base_environment); - } - Ok(environments) } pub async fn delete_environment( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let env = get_environment(window, id).await?; @@ -801,7 +844,9 @@ pub async fn delete_environment( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, env) + + emit_deleted_model(window, &AnyModel::Environment(env.to_owned()), update_source); + Ok(env) } const SETTINGS_ID: &str = "default"; @@ -822,8 +867,8 @@ async fn get_settings(mgr: &impl Manager) -> Result(mgr: &impl Manager) -> Settings { match get_settings(mgr).await { Ok(Some(settings)) => return settings, - Ok(None) => (), Err(e) => panic!("Failed to get settings {e:?}"), + Ok(None) => {} }; let dbm = &*mgr.state::(); @@ -843,6 +888,7 @@ pub async fn get_or_create_settings(mgr: &impl Manager) -> Settin pub async fn update_settings( window: &WebviewWindow, settings: Settings, + update_source: &UpdateSource, ) -> Result { // Correct for the bug where created_at was being updated by mistake let created_at = if settings.created_at > settings.updated_at { @@ -850,7 +896,7 @@ pub async fn update_settings( } else { settings.created_at }; - + let dbm = &*window.app_handle().state::(); let db = dbm.0.lock().await.get().unwrap(); @@ -884,13 +930,15 @@ pub async fn update_settings( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: Settings = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::Settings(m.to_owned()), update_source); + Ok(m) } pub async fn upsert_environment( window: &WebviewWindow, environment: Environment, + update_source: &UpdateSource, ) -> Result { let id = match environment.id.as_str() { "" => generate_model_id(ModelType::TypeEnvironment), @@ -934,8 +982,9 @@ pub async fn upsert_environment( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: Environment = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::Environment(m.to_owned()), update_source); + Ok(m) } pub async fn get_environment(mgr: &impl Manager, id: &str) -> Result { @@ -1001,6 +1050,7 @@ pub async fn list_plugins(mgr: &impl Manager) -> Result( window: &WebviewWindow, plugin: Plugin, + update_source: &UpdateSource, ) -> Result { let id = match plugin.id.as_str() { "" => generate_model_id(ModelType::TypePlugin), @@ -1044,11 +1094,17 @@ pub async fn upsert_plugin( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: Plugin = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::Plugin(m.to_owned()), update_source); + Ok(m) } -pub async fn delete_plugin(window: &WebviewWindow, id: &str) -> Result { +pub async fn delete_plugin( + window: &WebviewWindow, + id: &str, + + update_source: &UpdateSource, +) -> Result { let plugin = get_plugin(window, id).await?; let dbm = &*window.app_handle().state::(); @@ -1060,7 +1116,8 @@ pub async fn delete_plugin(window: &WebviewWindow, id: &str) -> R .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, plugin) + emit_deleted_model(window, &AnyModel::Plugin(plugin.to_owned()), update_source); + Ok(plugin) } pub async fn get_folder(mgr: &impl Manager, id: &str) -> Result { @@ -1094,7 +1151,12 @@ pub async fn list_folders( Ok(items.map(|v| v.unwrap()).collect()) } -pub async fn delete_folder(window: &WebviewWindow, id: &str) -> Result { +pub async fn delete_folder( + window: &WebviewWindow, + id: &str, + + update_source: &UpdateSource, +) -> Result { let folder = get_folder(window, id).await?; let dbm = &*window.app_handle().state::(); @@ -1106,10 +1168,16 @@ pub async fn delete_folder(window: &WebviewWindow, id: &str) -> R .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, folder) + emit_deleted_model(window, &AnyModel::Folder(folder.to_owned()), update_source); + Ok(folder) } -pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> Result { +pub async fn upsert_folder( + window: &WebviewWindow, + r: Folder, + + update_source: &UpdateSource, +) -> Result { let id = match r.id.as_str() { "" => generate_model_id(ModelType::TypeFolder), _ => r.id.to_string(), @@ -1156,13 +1224,15 @@ pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: Folder = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::Folder(m.to_owned()), update_source); + Ok(m) } pub async fn duplicate_http_request( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let mut request = match get_http_request(window, id).await? { None => return Err(ModelNotFound(id.to_string())), @@ -1170,7 +1240,7 @@ pub async fn duplicate_http_request( }; request.id = "".to_string(); request.sort_priority = request.sort_priority + 0.001; - upsert_http_request(window, request).await + upsert_http_request(window, request, update_source).await } pub async fn duplicate_folder( @@ -1201,6 +1271,7 @@ pub async fn duplicate_folder( sort_priority: src_folder.sort_priority + 0.001, ..src_folder.clone() }, + &UpdateSource::Window, ) .await?; @@ -1213,6 +1284,7 @@ pub async fn duplicate_folder( sort_priority: m.sort_priority + 0.001, ..m }, + &UpdateSource::Window, ) .await?; } @@ -1225,6 +1297,7 @@ pub async fn duplicate_folder( sort_priority: m.sort_priority + 0.001, ..m }, + &UpdateSource::Window, ) .await?; } @@ -1245,6 +1318,7 @@ pub async fn duplicate_folder( pub async fn upsert_http_request( window: &WebviewWindow, r: HttpRequest, + update_source: &UpdateSource, ) -> Result { let id = match r.id.as_str() { "" => generate_model_id(ModelType::TypeHttpRequest), @@ -1317,8 +1391,9 @@ pub async fn upsert_http_request( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: HttpRequest = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::HttpRequest(m.to_owned()), update_source); + Ok(m) } pub async fn list_http_requests( @@ -1357,6 +1432,7 @@ pub async fn get_http_request( pub async fn delete_http_request( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let req = match get_http_request(window, id).await? { None => return Err(ModelNotFound(id.to_string())), @@ -1364,7 +1440,7 @@ pub async fn delete_http_request( }; // DB deletes will cascade but this will delete the files - delete_all_http_responses_for_request(window, id).await?; + delete_all_http_responses_for_request(window, id, update_source).await?; let dbm = &*window.app_handle().state::(); let db = dbm.0.lock().await.get().unwrap(); @@ -1374,12 +1450,14 @@ pub async fn delete_http_request( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, req) + emit_deleted_model(window, &AnyModel::HttpRequest(req.to_owned()), update_source); + Ok(req) } pub async fn create_default_http_response( window: &WebviewWindow, request_id: &str, + update_source: &UpdateSource, ) -> Result { create_http_response( &window, @@ -1395,6 +1473,7 @@ pub async fn create_default_http_response( vec![], None, None, + update_source, ) .await } @@ -1414,11 +1493,12 @@ pub async fn create_http_response( headers: Vec, version: Option<&str>, remote_addr: Option<&str>, + update_source: &UpdateSource, ) -> Result { let responses = list_http_responses_for_request(window, request_id, None).await?; for response in responses.iter().skip(MAX_HTTP_RESPONSES_PER_REQUEST - 1) { debug!("Deleting old response {}", response.id); - delete_http_response(window, response.id.as_str()).await?; + delete_http_response(window, response.id.as_str(), update_source).await?; } let req = match get_http_request(window, request_id).await? { @@ -1471,8 +1551,9 @@ pub async fn create_http_response( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: HttpResponse = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::HttpResponse(m.to_owned()), update_source); + Ok(m) } pub async fn cancel_pending_grpc_connections(app: &AppHandle) -> Result<()> { @@ -1511,17 +1592,19 @@ pub async fn cancel_pending_responses(app: &AppHandle) -> Result<()> { pub async fn update_response_if_id( window: &WebviewWindow, response: &HttpResponse, + update_source: &UpdateSource, ) -> Result { if response.id.is_empty() { Ok(response.clone()) } else { - update_http_response(window, response).await + update_http_response(window, response, update_source).await } } pub async fn update_http_response( window: &WebviewWindow, response: &HttpResponse, + update_source: &UpdateSource, ) -> Result { let dbm = &*window.app_handle().state::(); let db = dbm.0.lock().await.get().unwrap(); @@ -1556,8 +1639,9 @@ pub async fn update_http_response( .build_rusqlite(SqliteQueryBuilder); let mut stmt = db.prepare(sql.as_str())?; - let m = stmt.query_row(&*params.as_params(), |row| row.try_into())?; - Ok(emit_upserted_model(window, m)) + let m: HttpResponse = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + emit_upserted_model(window, &AnyModel::HttpResponse(m.to_owned()), update_source); + Ok(m) } pub async fn get_http_response( @@ -1578,6 +1662,7 @@ pub async fn get_http_response( pub async fn delete_http_response( window: &WebviewWindow, id: &str, + update_source: &UpdateSource, ) -> Result { let resp = get_http_response(window, id).await?; @@ -1596,15 +1681,17 @@ pub async fn delete_http_response( .build_rusqlite(SqliteQueryBuilder); db.execute(sql.as_str(), &*params.as_params())?; - emit_deleted_model(window, resp) + emit_deleted_model(window, &AnyModel::HttpResponse(resp.to_owned()), update_source); + Ok(resp) } pub async fn delete_all_http_responses_for_request( window: &WebviewWindow, request_id: &str, + update_source: &UpdateSource, ) -> Result<()> { for r in list_http_responses_for_request(window, request_id, None).await? { - delete_http_response(window, &r.id).await?; + delete_http_response(window, &r.id, update_source).await?; } Ok(()) } @@ -1612,9 +1699,10 @@ pub async fn delete_all_http_responses_for_request( pub async fn delete_all_http_responses_for_workspace( window: &WebviewWindow, workspace_id: &str, + update_source: &UpdateSource, ) -> Result<()> { for r in list_http_responses_for_workspace(window, workspace_id, None).await? { - delete_http_response(window, &r.id).await?; + delete_http_response(window, &r.id, update_source).await?; } Ok(()) } @@ -1676,6 +1764,114 @@ pub async fn list_responses_by_workspace_id( Ok(items.map(|v| v.unwrap()).collect()) } +pub async fn get_sync_state_for_model( + mgr: &impl Manager, + workspace_id: &str, + model_id: &str, +) -> Result> { + let dbm = &*mgr.state::(); + let db = dbm.0.lock().await.get().unwrap(); + let (sql, params) = Query::select() + .from(SyncStateIden::Table) + .column(Asterisk) + .cond_where( + Cond::all() + .add(Expr::col(SyncStateIden::ModelId).eq(model_id)) + .add(Expr::col(SyncStateIden::WorkspaceId).eq(workspace_id)), + ) + .build_rusqlite(SqliteQueryBuilder); + let mut stmt = db.prepare(sql.as_str())?; + Ok(stmt.query_row(&*params.as_params(), |row| row.try_into()).optional()?) +} + +pub async fn list_sync_states_for_workspace( + mgr: &impl Manager, + workspace_id: &str, + sync_dir: PathBuf, +) -> Result> { + let dbm = &*mgr.state::(); + let db = dbm.0.lock().await.get().unwrap(); + let (sql, params) = Query::select() + .from(SyncStateIden::Table) + .column(Asterisk) + .cond_where( + Cond::all() + .add(Expr::col(SyncStateIden::WorkspaceId).eq(workspace_id)) + .add(Expr::col(SyncStateIden::SyncDir).eq(sync_dir.to_string_lossy())), + ) + .build_rusqlite(SqliteQueryBuilder); + let mut stmt = db.prepare(sql.as_str())?; + let items = stmt.query_map(&*params.as_params(), |row| row.try_into())?; + Ok(items.map(|v| v.unwrap()).collect()) +} + +pub async fn upsert_sync_state( + mgr: &impl Manager, + sync_state: SyncState, +) -> Result { + let id = match sync_state.id.as_str() { + "" => generate_model_id(ModelType::TypeSyncState), + _ => sync_state.id.to_string(), + }; + + let dbm = &*mgr.state::(); + let db = dbm.0.lock().await.get().unwrap(); + + let (sql, params) = Query::insert() + .into_table(SyncStateIden::Table) + .columns([ + SyncStateIden::Id, + SyncStateIden::WorkspaceId, + SyncStateIden::CreatedAt, + SyncStateIden::UpdatedAt, + SyncStateIden::FlushedAt, + SyncStateIden::Checksum, + SyncStateIden::ModelId, + SyncStateIden::RelPath, + SyncStateIden::SyncDir, + ]) + .values_panic([ + id.as_str().into(), + sync_state.workspace_id.into(), + CurrentTimestamp.into(), + CurrentTimestamp.into(), + sync_state.flushed_at.into(), + sync_state.checksum.into(), + sync_state.model_id.into(), + sync_state.rel_path.into(), + sync_state.sync_dir.into(), + ]) + .on_conflict( + OnConflict::columns(vec![SyncStateIden::WorkspaceId, SyncStateIden::ModelId]) + .update_columns([ + SyncStateIden::UpdatedAt, + SyncStateIden::FlushedAt, + SyncStateIden::Checksum, + SyncStateIden::RelPath, + SyncStateIden::SyncDir, + ]) + .to_owned(), + ) + .returning_all() + .build_rusqlite(SqliteQueryBuilder); + + let mut stmt = db.prepare(sql.as_str())?; + let m: SyncState = stmt.query_row(&*params.as_params(), |row| row.try_into())?; + Ok(m) +} + +pub async fn delete_sync_state(mgr: &impl Manager, id: &str) -> Result<()> { + let dbm = &*mgr.app_handle().state::(); + let db = dbm.0.lock().await.get().unwrap(); + + let (sql, params) = Query::delete() + .from_table(SyncStateIden::Table) + .cond_where(Expr::col(SyncStateIden::Id).eq(id)) + .build_rusqlite(SqliteQueryBuilder); + db.execute(sql.as_str(), &*params.as_params())?; + Ok(()) +} + pub async fn debug_pool(mgr: &impl Manager) { let dbm = &*mgr.state::(); let db = dbm.0.lock().await; @@ -1688,34 +1884,212 @@ pub fn generate_model_id(model: ModelType) -> String { } pub fn generate_id() -> String { - Alphanumeric.sample_string(&mut rand::thread_rng(), 10) + let alphabet: [char; 57] = [ + '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', + ]; + + nanoid!(10, &alphabet) } -#[derive(Clone, Serialize)] -#[serde(default, rename_all = "camelCase")] -struct ModelPayload { - pub model: M, +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "models.ts")] +pub struct ModelPayload { + pub model: AnyModel, pub window_label: String, + pub update_source: UpdateSource, } -fn emit_upserted_model(window: &WebviewWindow, model: M) -> M { +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "snake_case")] +#[ts(export, export_to = "models.ts")] +pub enum UpdateSource { + Sync, + Window, + Plugin, + Background, +} + +fn emit_upserted_model( + window: &WebviewWindow, + model: &AnyModel, + update_source: &UpdateSource, +) { let payload = ModelPayload { - model: model.clone(), + model: model.to_owned(), window_label: window.label().to_string(), + update_source: update_source.to_owned(), }; window.emit("upserted_model", payload).unwrap(); - model } -fn emit_deleted_model( +fn emit_deleted_model( window: &WebviewWindow, - model: M, -) -> Result { + model: &AnyModel, + update_source: &UpdateSource, +) { let payload = ModelPayload { - model: model.clone(), + model: model.to_owned(), window_label: window.label().to_string(), + update_source: update_source.to_owned(), }; window.emit("deleted_model", payload).unwrap(); - Ok(model) +} + +pub fn listen_to_model_delete(app_handle: &AppHandle, handler: F) +where + F: Fn(ModelPayload) + Send + 'static, + R: Runtime, +{ + app_handle.listen_any("deleted_model", move |e| { + match serde_json::from_str(e.payload()) { + Ok(payload) => handler(payload), + Err(e) => { + warn!("Failed to deserialize deleted model {}", e); + return; + } + }; + }); +} + +pub fn listen_to_model_upsert(app_handle: &AppHandle, handler: F) +where + F: Fn(ModelPayload) + Send + 'static, + R: Runtime, +{ + app_handle.listen_any("upserted_model", move |e| { + match serde_json::from_str(e.payload()) { + Ok(payload) => handler(payload), + Err(e) => { + warn!("Failed to deserialize upserted model {}", e); + return; + } + }; + }); +} + +#[derive(Default, Debug, Deserialize, Serialize)] +#[serde(default, rename_all = "camelCase")] +pub struct WorkspaceExport { + pub yaak_version: String, + pub yaak_schema: i64, + pub timestamp: NaiveDateTime, + pub resources: BatchUpsertResult, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +#[serde(default, rename_all = "camelCase")] +pub struct BatchUpsertResult { + pub workspaces: Vec, + pub environments: Vec, + pub folders: Vec, + pub http_requests: Vec, + pub grpc_requests: Vec, +} + +pub async fn batch_upsert( + window: &WebviewWindow, + workspaces: Vec, + environments: Vec, + folders: Vec, + http_requests: Vec, + grpc_requests: Vec, +) -> Result { + let mut imported_resources = BatchUpsertResult::default(); + + for v in workspaces { + let x = upsert_workspace(&window, v, &UpdateSource::Window).await?; + imported_resources.workspaces.push(x.clone()); + } + info!("Imported {} workspaces", imported_resources.workspaces.len()); + + while imported_resources.environments.len() < environments.len() { + for v in environments.clone() { + if let Some(fid) = v.environment_id.clone() { + let imported_parent = imported_resources.environments.iter().find(|f| f.id == fid); + if imported_parent.is_none() { + continue; + } + } + if let Some(_) = imported_resources.environments.iter().find(|f| f.id == v.id) { + continue; + } + let x = upsert_environment(&window, v, &UpdateSource::Window).await?; + imported_resources.environments.push(x.clone()); + } + } + info!("Imported {} environments", imported_resources.environments.len()); + + while imported_resources.folders.len() < folders.len() { + for v in folders.clone() { + if let Some(fid) = v.folder_id.clone() { + let imported_parent = imported_resources.folders.iter().find(|f| f.id == fid); + if imported_parent.is_none() { + continue; + } + } + if let Some(_) = imported_resources.folders.iter().find(|f| f.id == v.id) { + continue; + } + let x = upsert_folder(&window, v, &UpdateSource::Window).await?; + imported_resources.folders.push(x.clone()); + } + } + info!("Imported {} folders", imported_resources.folders.len()); + + for v in http_requests { + let x = upsert_http_request(&window, v, &UpdateSource::Window).await?; + imported_resources.http_requests.push(x.clone()); + } + info!("Imported {} http_requests", imported_resources.http_requests.len()); + + for v in grpc_requests { + let x = upsert_grpc_request(&window, v, &UpdateSource::Window).await?; + imported_resources.grpc_requests.push(x.clone()); + } + info!("Imported {} grpc_requests", imported_resources.grpc_requests.len()); + + Ok(imported_resources) +} + +pub async fn get_workspace_export_resources( + mgr: &impl Manager, + workspace_ids: Vec<&str>, +) -> WorkspaceExport { + let mut data = WorkspaceExport { + yaak_version: mgr.package_info().version.clone().to_string(), + yaak_schema: 2, + timestamp: chrono::Utc::now().naive_utc(), + resources: BatchUpsertResult { + workspaces: Vec::new(), + environments: Vec::new(), + folders: Vec::new(), + http_requests: Vec::new(), + grpc_requests: Vec::new(), + }, + }; + + for workspace_id in workspace_ids { + data.resources + .workspaces + .push(get_workspace(mgr, workspace_id).await.expect("Failed to get workspace")); + data.resources.environments.append( + &mut list_environments(mgr, workspace_id).await.expect("Failed to get environments"), + ); + data.resources + .folders + .append(&mut list_folders(mgr, workspace_id).await.expect("Failed to get folders")); + data.resources.http_requests.append( + &mut list_http_requests(mgr, workspace_id).await.expect("Failed to get http requests"), + ); + data.resources.grpc_requests.append( + &mut list_grpc_requests(mgr, workspace_id).await.expect("Failed to get grpc requests"), + ); + } + + data } diff --git a/src-tauri/yaak_plugin_runtime/Cargo.toml b/src-tauri/yaak-plugins/Cargo.toml similarity index 85% rename from src-tauri/yaak_plugin_runtime/Cargo.toml rename to src-tauri/yaak-plugins/Cargo.toml index 2dc7b6f9..18503354 100644 --- a/src-tauri/yaak_plugin_runtime/Cargo.toml +++ b/src-tauri/yaak-plugins/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "yaak_plugin_runtime" +name = "yaak-plugins" version = "0.1.0" edition = "2021" publish = false @@ -16,8 +16,8 @@ tauri-plugin-shell = { workspace = true } tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "process"] } tonic = "0.12.1" ts-rs = "10.0.0" -thiserror = "1.0.63" -yaak_models = { workspace = true } +thiserror = "2.0.7" +yaak-models = { workspace = true } regex = "1.10.6" path-slash = "0.2.1" diff --git a/src-tauri/yaak_plugin_runtime/bindings/events.ts b/src-tauri/yaak-plugins/bindings/events.ts similarity index 98% rename from src-tauri/yaak_plugin_runtime/bindings/events.ts rename to src-tauri/yaak-plugins/bindings/events.ts index 65a536b0..75268516 100644 --- a/src-tauri/yaak_plugin_runtime/bindings/events.ts +++ b/src-tauri/yaak-plugins/bindings/events.ts @@ -114,7 +114,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** @@ -132,7 +132,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** @@ -158,7 +158,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** @@ -176,7 +176,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** @@ -198,7 +198,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** @@ -222,7 +222,7 @@ name: string, */ optional?: boolean, /** - * The label of the input + * The label of the input */ label?: string, /** diff --git a/src-tauri/yaak_plugin_runtime/bindings/models.ts b/src-tauri/yaak-plugins/bindings/models.ts similarity index 97% rename from src-tauri/yaak_plugin_runtime/bindings/models.ts rename to src-tauri/yaak-plugins/bindings/models.ts index 518443ed..ec8b4315 100644 --- a/src-tauri/yaak_plugin_runtime/bindings/models.ts +++ b/src-tauri/yaak-plugins/bindings/models.ts @@ -22,4 +22,4 @@ export type HttpResponseState = "initialized" | "connected" | "closed"; export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id: string, }; -export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, }; +export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, settingSyncDir: string | null, }; diff --git a/src-tauri/yaak_plugin_runtime/bindings/serde_json/JsonValue.ts b/src-tauri/yaak-plugins/bindings/serde_json/JsonValue.ts similarity index 100% rename from src-tauri/yaak_plugin_runtime/bindings/serde_json/JsonValue.ts rename to src-tauri/yaak-plugins/bindings/serde_json/JsonValue.ts diff --git a/src-tauri/yaak_plugin_runtime/build.rs b/src-tauri/yaak-plugins/build.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/build.rs rename to src-tauri/yaak-plugins/build.rs diff --git a/src-tauri/yaak_plugin_runtime/index.ts b/src-tauri/yaak-plugins/index.ts similarity index 100% rename from src-tauri/yaak_plugin_runtime/index.ts rename to src-tauri/yaak-plugins/index.ts diff --git a/src-tauri/yaak-plugins/package.json b/src-tauri/yaak-plugins/package.json new file mode 100644 index 00000000..e48f823a --- /dev/null +++ b/src-tauri/yaak-plugins/package.json @@ -0,0 +1,6 @@ +{ + "name": "@yaakapp-internal/plugins", + "private": true, + "version": "1.0.0", + "main": "index.ts" +} diff --git a/src-tauri/yaak_plugin_runtime/src/error.rs b/src-tauri/yaak-plugins/src/error.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/error.rs rename to src-tauri/yaak-plugins/src/error.rs diff --git a/src-tauri/yaak_plugin_runtime/src/events.rs b/src-tauri/yaak-plugins/src/events.rs similarity index 99% rename from src-tauri/yaak_plugin_runtime/src/events.rs rename to src-tauri/yaak-plugins/src/events.rs index fc1d1478..73afddaa 100644 --- a/src-tauri/yaak_plugin_runtime/src/events.rs +++ b/src-tauri/yaak-plugins/src/events.rs @@ -296,7 +296,7 @@ pub struct TemplateFunction { pub name: String, #[ts(optional)] pub description: Option, - + /// Also support alternative names. This is useful for not breaking existing /// tags when changing the `name` property #[ts(optional)] @@ -321,15 +321,15 @@ pub enum TemplateFunctionArg { pub struct TemplateFunctionBaseArg { /// The name of the argument. Should be `camelCase` format pub name: String, - + /// Whether the user must fill in the argument #[ts(optional)] pub optional: Option, - - /// The label of the input + + /// The label of the input #[ts(optional)] pub label: Option, - + /// The default value #[ts(optional)] pub default_value: Option, @@ -341,7 +341,7 @@ pub struct TemplateFunctionBaseArg { pub struct TemplateFunctionTextArg { #[serde(flatten)] pub base: TemplateFunctionBaseArg, - + /// Placeholder for the text input #[ts(optional)] pub placeholder: Option, @@ -361,22 +361,22 @@ pub struct TemplateFunctionHttpRequestArg { pub struct TemplateFunctionFileArg { #[serde(flatten)] pub base: TemplateFunctionBaseArg, - + /// The title of the file selection window pub title: String, - + /// Allow selecting multiple files #[ts(optional)] pub multiple: Option, - + // Select a directory, not a file #[ts(optional)] pub directory: Option, - + // Default file path for selection dialog #[ts(optional)] pub default_path: Option, - + // Specify to only allow selection of certain file extensions #[ts(optional)] pub filters: Option>, @@ -397,7 +397,7 @@ pub struct OpenFileFilter { pub struct TemplateFunctionSelectArg { #[serde(flatten)] pub base: TemplateFunctionBaseArg, - + /// The options that will be available in the select input pub options: Vec, } diff --git a/src-tauri/yaak_plugin_runtime/src/plugin.rs b/src-tauri/yaak-plugins/src/lib.rs similarity index 87% rename from src-tauri/yaak_plugin_runtime/src/plugin.rs rename to src-tauri/yaak-plugins/src/lib.rs index 86f3a23e..d9a26853 100644 --- a/src-tauri/yaak_plugin_runtime/src/plugin.rs +++ b/src-tauri/yaak-plugins/src/lib.rs @@ -1,11 +1,19 @@ -use crate::manager::PluginManager; -use log::info; use std::process::exit; +use log::info; use tauri::plugin::{Builder, TauriPlugin}; use tauri::{Manager, RunEvent, Runtime, State}; +use crate::manager::PluginManager; + +pub mod error; +pub mod events; +pub mod manager; +mod nodejs; +mod server; +pub mod plugin_handle; +mod util; pub fn init() -> TauriPlugin { - Builder::new("yaak_plugin_runtime") + Builder::new("yaak-plugins") .setup(|app_handle, _| { let manager = PluginManager::new(app_handle.clone()); app_handle.manage(manager.clone()); diff --git a/src-tauri/yaak_plugin_runtime/src/manager.rs b/src-tauri/yaak-plugins/src/manager.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/manager.rs rename to src-tauri/yaak-plugins/src/manager.rs diff --git a/src-tauri/yaak_plugin_runtime/src/nodejs.rs b/src-tauri/yaak-plugins/src/nodejs.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/nodejs.rs rename to src-tauri/yaak-plugins/src/nodejs.rs diff --git a/src-tauri/yaak_plugin_runtime/src/plugin_handle.rs b/src-tauri/yaak-plugins/src/plugin_handle.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/plugin_handle.rs rename to src-tauri/yaak-plugins/src/plugin_handle.rs diff --git a/src-tauri/yaak_plugin_runtime/src/server.rs b/src-tauri/yaak-plugins/src/server.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/server.rs rename to src-tauri/yaak-plugins/src/server.rs diff --git a/src-tauri/yaak_plugin_runtime/src/util.rs b/src-tauri/yaak-plugins/src/util.rs similarity index 100% rename from src-tauri/yaak_plugin_runtime/src/util.rs rename to src-tauri/yaak-plugins/src/util.rs diff --git a/src-tauri/yaak_sse/Cargo.toml b/src-tauri/yaak-sse/Cargo.toml similarity index 91% rename from src-tauri/yaak_sse/Cargo.toml rename to src-tauri/yaak-sse/Cargo.toml index 431cf85c..88b3652c 100644 --- a/src-tauri/yaak_sse/Cargo.toml +++ b/src-tauri/yaak-sse/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "yaak_sse" +name = "yaak-sse" version = "0.1.0" edition = "2021" publish = false diff --git a/src-tauri/yaak_sse/bindings/sse.ts b/src-tauri/yaak-sse/bindings/sse.ts similarity index 100% rename from src-tauri/yaak_sse/bindings/sse.ts rename to src-tauri/yaak-sse/bindings/sse.ts diff --git a/src-tauri/yaak_sse/index.ts b/src-tauri/yaak-sse/index.ts similarity index 100% rename from src-tauri/yaak_sse/index.ts rename to src-tauri/yaak-sse/index.ts diff --git a/src-tauri/yaak_sse/package.json b/src-tauri/yaak-sse/package.json similarity index 100% rename from src-tauri/yaak_sse/package.json rename to src-tauri/yaak-sse/package.json diff --git a/src-tauri/yaak_sse/src/lib.rs b/src-tauri/yaak-sse/src/lib.rs similarity index 100% rename from src-tauri/yaak_sse/src/lib.rs rename to src-tauri/yaak-sse/src/lib.rs diff --git a/src-tauri/yaak_sse/src/sse.rs b/src-tauri/yaak-sse/src/sse.rs similarity index 100% rename from src-tauri/yaak_sse/src/sse.rs rename to src-tauri/yaak-sse/src/sse.rs diff --git a/src-tauri/yaak-sync/Cargo.toml b/src-tauri/yaak-sync/Cargo.toml new file mode 100644 index 00000000..4e7fff0a --- /dev/null +++ b/src-tauri/yaak-sync/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "yaak-sync" +links = "yaak-sync" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +yaak-models = { workspace = true } +chrono = { version = "0.4.38", features = ["serde"] } +serde = { version = "1.0.215", features = ["derive"] } +tauri = { workspace = true } +thiserror = { workspace = true } +ts-rs = { workspace = true, features = ["chrono-impl", "serde-json-impl"] } +serde_yaml = "0.9.34" +log = "0.4.22" +serde_json = "1.0.132" +hex = "0.4.3" +sha1 = "0.10.6" + +[build-dependencies] +tauri-plugin = { version = "2.0.3", features = ["build"] } diff --git a/src-tauri/yaak-sync/bindings/git.ts b/src-tauri/yaak-sync/bindings/git.ts new file mode 100644 index 00000000..50b23968 --- /dev/null +++ b/src-tauri/yaak-sync/bindings/git.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type GitCommit = { author: string, when: string, message: string | null, }; + +export type GitStatus = "added" | "conflict" | "current" | "modified" | "removed" | "renamed" | "type_change"; + +export type GitStatusEntry = { relaPath: string, status: GitStatus, staged: boolean, prev: string | null, next: string | null, }; diff --git a/src-tauri/yaak-sync/bindings/models.ts b/src-tauri/yaak-sync/bindings/models.ts new file mode 100644 index 00000000..ebc35ccd --- /dev/null +++ b/src-tauri/yaak-sync/bindings/models.ts @@ -0,0 +1,23 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Environment = { model: "environment", id: string, workspaceId: string, environmentId: string | null, createdAt: string, updatedAt: string, name: string, variables: Array, }; + +export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id: string, }; + +export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, name: string, description: string, sortPriority: number, }; + +export type GrpcMetadataEntry = { enabled?: boolean, name: string, value: string, id: string, }; + +export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record, description: string, message: string, metadata: Array, method: string | null, name: string, service: string | null, sortPriority: number, url: string, }; + +export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, body: Record, bodyType: string | null, description: string, headers: Array, method: string, name: string, sortPriority: number, url: string, urlParameters: Array, }; + +export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, id: string, }; + +export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id: string, }; + +export type SyncModel = { "type": "workspace" } & Workspace | { "type": "environment" } & Environment | { "type": "folder" } & Folder | { "type": "http_request" } & HttpRequest | { "type": "grpc_request" } & GrpcRequest; + +export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, }; + +export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, settingSyncDir: string | null, }; diff --git a/src-tauri/yaak-sync/bindings/sync.ts b/src-tauri/yaak-sync/bindings/sync.ts new file mode 100644 index 00000000..e486cc48 --- /dev/null +++ b/src-tauri/yaak-sync/bindings/sync.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SyncModel } from "./models"; +import type { SyncState } from "./models"; + +export type FsCandidate = { "type": "FsCandidate", model: SyncModel, relPath: string, checksum: string, }; + +export type SyncOp = { "type": "fsCreate", model: SyncModel, } | { "type": "fsUpdate", model: SyncModel, state: SyncState, } | { "type": "fsDelete", state: SyncState, fs: FsCandidate | null, } | { "type": "dbCreate", fs: FsCandidate, } | { "type": "dbUpdate", state: SyncState, fs: FsCandidate, } | { "type": "dbDelete", model: SyncModel, state: SyncState, }; diff --git a/src-tauri/yaak-sync/build.rs b/src-tauri/yaak-sync/build.rs new file mode 100644 index 00000000..e41e7d0a --- /dev/null +++ b/src-tauri/yaak-sync/build.rs @@ -0,0 +1,5 @@ +const COMMANDS: &[&str] = &["calculate", "apply"]; + +fn main() { + tauri_plugin::Builder::new(COMMANDS).build(); +} diff --git a/src-tauri/yaak-sync/index.ts b/src-tauri/yaak-sync/index.ts new file mode 100644 index 00000000..9b9a1911 --- /dev/null +++ b/src-tauri/yaak-sync/index.ts @@ -0,0 +1,20 @@ +import { invoke } from '@tauri-apps/api/core'; +import { Workspace } from '@yaakapp-internal/models'; +import { SyncOp } from './bindings/sync'; + +export const calculateSync = async (workspace: Workspace) => { + if (!workspace.settingSyncDir) throw new Error("Workspace sync dir not configured"); + + return invoke('plugin:yaak-sync|calculate', { + workspaceId: workspace.id, + dir: workspace.settingSyncDir, + }); +}; + +export const applySync = async (workspace: Workspace, ops: SyncOp[]) => { + console.log('Applying sync', ops); + return invoke('plugin:yaak-sync|apply', { + workspaceId: workspace.id, + dir: workspace.settingSyncDir, + }); +}; diff --git a/src-tauri/yaak_plugin_runtime/package.json b/src-tauri/yaak-sync/package.json similarity index 63% rename from src-tauri/yaak_plugin_runtime/package.json rename to src-tauri/yaak-sync/package.json index beb61b6b..79c0b9c9 100644 --- a/src-tauri/yaak_plugin_runtime/package.json +++ b/src-tauri/yaak-sync/package.json @@ -1,5 +1,5 @@ { - "name": "@yaakapp-internal/plugin", + "name": "@yaakapp-internal/sync", "private": true, "version": "1.0.0", "main": "index.ts" diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/activate.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/activate.toml new file mode 100644 index 00000000..e35d3ece --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/activate.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-activate" +description = "Enables the activate command without any pre-configured scope." +commands.allow = ["activate"] + +[[permission]] +identifier = "deny-activate" +description = "Denies the activate command without any pre-configured scope." +commands.deny = ["activate"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/add.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/add.toml new file mode 100644 index 00000000..5ce53ad8 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/add.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-add" +description = "Enables the add command without any pre-configured scope." +commands.allow = ["add"] + +[[permission]] +identifier = "deny-add" +description = "Denies the add command without any pre-configured scope." +commands.deny = ["add"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/apply.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/apply.toml new file mode 100644 index 00000000..ce466966 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/apply.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-apply" +description = "Enables the apply command without any pre-configured scope." +commands.allow = ["apply"] + +[[permission]] +identifier = "deny-apply" +description = "Denies the apply command without any pre-configured scope." +commands.deny = ["apply"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/calculate.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/calculate.toml new file mode 100644 index 00000000..87039985 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/calculate.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-calculate" +description = "Enables the calculate command without any pre-configured scope." +commands.allow = ["calculate"] + +[[permission]] +identifier = "deny-calculate" +description = "Denies the calculate command without any pre-configured scope." +commands.deny = ["calculate"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/check.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/check.toml new file mode 100644 index 00000000..fca73ce9 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/check.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-check" +description = "Enables the check command without any pre-configured scope." +commands.allow = ["check"] + +[[permission]] +identifier = "deny-check" +description = "Denies the check command without any pre-configured scope." +commands.deny = ["check"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/checkout.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/checkout.toml new file mode 100644 index 00000000..c523af1a --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/checkout.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-checkout" +description = "Enables the checkout command without any pre-configured scope." +commands.allow = ["checkout"] + +[[permission]] +identifier = "deny-checkout" +description = "Denies the checkout command without any pre-configured scope." +commands.deny = ["checkout"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_add.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_add.toml new file mode 100644 index 00000000..f6142ec3 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_add.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-add" +description = "Enables the cmd_add command without any pre-configured scope." +commands.allow = ["cmd_add"] + +[[permission]] +identifier = "deny-cmd-add" +description = "Denies the cmd_add command without any pre-configured scope." +commands.deny = ["cmd_add"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_checkout.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_checkout.toml new file mode 100644 index 00000000..71814ad3 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_checkout.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-checkout" +description = "Enables the cmd_checkout command without any pre-configured scope." +commands.allow = ["cmd_checkout"] + +[[permission]] +identifier = "deny-cmd-checkout" +description = "Denies the cmd_checkout command without any pre-configured scope." +commands.deny = ["cmd_checkout"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_commit.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_commit.toml new file mode 100644 index 00000000..395f3805 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_commit.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-commit" +description = "Enables the cmd_commit command without any pre-configured scope." +commands.allow = ["cmd_commit"] + +[[permission]] +identifier = "deny-cmd-commit" +description = "Denies the cmd_commit command without any pre-configured scope." +commands.deny = ["cmd_commit"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_init.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_init.toml new file mode 100644 index 00000000..4620a90c --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_init.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-init" +description = "Enables the cmd_init command without any pre-configured scope." +commands.allow = ["cmd_init"] + +[[permission]] +identifier = "deny-cmd-init" +description = "Denies the cmd_init command without any pre-configured scope." +commands.deny = ["cmd_init"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_log.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_log.toml new file mode 100644 index 00000000..feb77e19 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_log.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-log" +description = "Enables the cmd_log command without any pre-configured scope." +commands.allow = ["cmd_log"] + +[[permission]] +identifier = "deny-cmd-log" +description = "Denies the cmd_log command without any pre-configured scope." +commands.deny = ["cmd_log"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_status.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_status.toml new file mode 100644 index 00000000..51afe4dd --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/cmd_status.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-cmd-status" +description = "Enables the cmd_status command without any pre-configured scope." +commands.allow = ["cmd_status"] + +[[permission]] +identifier = "deny-cmd-status" +description = "Denies the cmd_status command without any pre-configured scope." +commands.deny = ["cmd_status"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/commit.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/commit.toml new file mode 100644 index 00000000..b8600e92 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/commit.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-commit" +description = "Enables the commit command without any pre-configured scope." +commands.allow = ["commit"] + +[[permission]] +identifier = "deny-commit" +description = "Denies the commit command without any pre-configured scope." +commands.deny = ["commit"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/init.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/init.toml new file mode 100644 index 00000000..9cbfb9f8 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/init.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-init" +description = "Enables the init command without any pre-configured scope." +commands.allow = ["init"] + +[[permission]] +identifier = "deny-init" +description = "Denies the init command without any pre-configured scope." +commands.deny = ["init"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/init_repo.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/init_repo.toml new file mode 100644 index 00000000..55bb601a --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/init_repo.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-init-repo" +description = "Enables the init_repo command without any pre-configured scope." +commands.allow = ["init_repo"] + +[[permission]] +identifier = "deny-init-repo" +description = "Denies the init_repo command without any pre-configured scope." +commands.deny = ["init_repo"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/initialize.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/initialize.toml new file mode 100644 index 00000000..73961d13 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/initialize.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-initialize" +description = "Enables the initialize command without any pre-configured scope." +commands.allow = ["initialize"] + +[[permission]] +identifier = "deny-initialize" +description = "Denies the initialize command without any pre-configured scope." +commands.deny = ["initialize"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/log.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/log.toml new file mode 100644 index 00000000..ba36eff5 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/log.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-log" +description = "Enables the log command without any pre-configured scope." +commands.allow = ["log"] + +[[permission]] +identifier = "deny-log" +description = "Denies the log command without any pre-configured scope." +commands.deny = ["log"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/status.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/status.toml new file mode 100644 index 00000000..c8ed433c --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/status.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-status" +description = "Enables the status command without any pre-configured scope." +commands.allow = ["status"] + +[[permission]] +identifier = "deny-status" +description = "Denies the status command without any pre-configured scope." +commands.deny = ["status"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/sync.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/sync.toml new file mode 100644 index 00000000..4e616afd --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/sync.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-sync" +description = "Enables the sync command without any pre-configured scope." +commands.allow = ["sync"] + +[[permission]] +identifier = "deny-sync" +description = "Denies the sync command without any pre-configured scope." +commands.deny = ["sync"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/sync_fs.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/sync_fs.toml new file mode 100644 index 00000000..e5eb556e --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/sync_fs.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-sync-fs" +description = "Enables the sync_fs command without any pre-configured scope." +commands.allow = ["sync_fs"] + +[[permission]] +identifier = "deny-sync-fs" +description = "Denies the sync_fs command without any pre-configured scope." +commands.deny = ["sync_fs"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/commands/unstage.toml b/src-tauri/yaak-sync/permissions/autogenerated/commands/unstage.toml new file mode 100644 index 00000000..cbf33ce2 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/commands/unstage.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-unstage" +description = "Enables the unstage command without any pre-configured scope." +commands.allow = ["unstage"] + +[[permission]] +identifier = "deny-unstage" +description = "Denies the unstage command without any pre-configured scope." +commands.deny = ["unstage"] diff --git a/src-tauri/yaak-sync/permissions/autogenerated/reference.md b/src-tauri/yaak-sync/permissions/autogenerated/reference.md new file mode 100644 index 00000000..1a4484b1 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/autogenerated/reference.md @@ -0,0 +1,562 @@ +## Default Permission + +Default permissions for the plugin + +- `allow-calculate` +- `allow-apply` + +## Permission Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdentifierDescription
+ +`yaak-sync:allow-activate` + + + +Enables the activate command without any pre-configured scope. + +
+ +`yaak-sync:deny-activate` + + + +Denies the activate command without any pre-configured scope. + +
+ +`yaak-sync:allow-add` + + + +Enables the add command without any pre-configured scope. + +
+ +`yaak-sync:deny-add` + + + +Denies the add command without any pre-configured scope. + +
+ +`yaak-sync:allow-apply` + + + +Enables the apply command without any pre-configured scope. + +
+ +`yaak-sync:deny-apply` + + + +Denies the apply command without any pre-configured scope. + +
+ +`yaak-sync:allow-calculate` + + + +Enables the calculate command without any pre-configured scope. + +
+ +`yaak-sync:deny-calculate` + + + +Denies the calculate command without any pre-configured scope. + +
+ +`yaak-sync:allow-check` + + + +Enables the check command without any pre-configured scope. + +
+ +`yaak-sync:deny-check` + + + +Denies the check command without any pre-configured scope. + +
+ +`yaak-sync:allow-checkout` + + + +Enables the checkout command without any pre-configured scope. + +
+ +`yaak-sync:deny-checkout` + + + +Denies the checkout command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-add` + + + +Enables the cmd_add command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-add` + + + +Denies the cmd_add command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-checkout` + + + +Enables the cmd_checkout command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-checkout` + + + +Denies the cmd_checkout command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-commit` + + + +Enables the cmd_commit command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-commit` + + + +Denies the cmd_commit command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-init` + + + +Enables the cmd_init command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-init` + + + +Denies the cmd_init command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-log` + + + +Enables the cmd_log command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-log` + + + +Denies the cmd_log command without any pre-configured scope. + +
+ +`yaak-sync:allow-cmd-status` + + + +Enables the cmd_status command without any pre-configured scope. + +
+ +`yaak-sync:deny-cmd-status` + + + +Denies the cmd_status command without any pre-configured scope. + +
+ +`yaak-sync:allow-commit` + + + +Enables the commit command without any pre-configured scope. + +
+ +`yaak-sync:deny-commit` + + + +Denies the commit command without any pre-configured scope. + +
+ +`yaak-sync:allow-init` + + + +Enables the init command without any pre-configured scope. + +
+ +`yaak-sync:deny-init` + + + +Denies the init command without any pre-configured scope. + +
+ +`yaak-sync:allow-init-repo` + + + +Enables the init_repo command without any pre-configured scope. + +
+ +`yaak-sync:deny-init-repo` + + + +Denies the init_repo command without any pre-configured scope. + +
+ +`yaak-sync:allow-initialize` + + + +Enables the initialize command without any pre-configured scope. + +
+ +`yaak-sync:deny-initialize` + + + +Denies the initialize command without any pre-configured scope. + +
+ +`yaak-sync:allow-log` + + + +Enables the log command without any pre-configured scope. + +
+ +`yaak-sync:deny-log` + + + +Denies the log command without any pre-configured scope. + +
+ +`yaak-sync:allow-status` + + + +Enables the status command without any pre-configured scope. + +
+ +`yaak-sync:deny-status` + + + +Denies the status command without any pre-configured scope. + +
+ +`yaak-sync:allow-sync` + + + +Enables the sync command without any pre-configured scope. + +
+ +`yaak-sync:deny-sync` + + + +Denies the sync command without any pre-configured scope. + +
+ +`yaak-sync:allow-sync-fs` + + + +Enables the sync_fs command without any pre-configured scope. + +
+ +`yaak-sync:deny-sync-fs` + + + +Denies the sync_fs command without any pre-configured scope. + +
+ +`yaak-sync:allow-unstage` + + + +Enables the unstage command without any pre-configured scope. + +
+ +`yaak-sync:deny-unstage` + + + +Denies the unstage command without any pre-configured scope. + +
diff --git a/src-tauri/yaak-sync/permissions/default.toml b/src-tauri/yaak-sync/permissions/default.toml new file mode 100644 index 00000000..2562aa14 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/default.toml @@ -0,0 +1,6 @@ +[default] +description = "Default permissions for the plugin" +permissions = [ + "allow-calculate", + "allow-apply", +] diff --git a/src-tauri/yaak-sync/permissions/schemas/schema.json b/src-tauri/yaak-sync/permissions/schemas/schema.json new file mode 100644 index 00000000..b3d38fa1 --- /dev/null +++ b/src-tauri/yaak-sync/permissions/schemas/schema.json @@ -0,0 +1,515 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "PermissionFile", + "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.", + "type": "object", + "properties": { + "default": { + "description": "The default permission set for the plugin", + "anyOf": [ + { + "$ref": "#/definitions/DefaultPermission" + }, + { + "type": "null" + } + ] + }, + "set": { + "description": "A list of permissions sets defined", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionSet" + } + }, + "permission": { + "description": "A list of inlined permissions", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + } + } + }, + "definitions": { + "DefaultPermission": { + "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", + "type": "object", + "required": [ + "permissions" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "description": { + "description": "Human-readable description of what the permission does. Tauri convention is to use

headings in markdown content for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionSet": { + "description": "A set of direct permissions grouped together under a new name.", + "type": "object", + "required": [ + "description", + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does.", + "type": "string" + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionKind" + } + } + } + }, + "Permission": { + "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does. Tauri internal convention is to use

headings in markdown content for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "commands": { + "description": "Allowed or denied commands when using this permission.", + "default": { + "allow": [], + "deny": [] + }, + "allOf": [ + { + "$ref": "#/definitions/Commands" + } + ] + }, + "scope": { + "description": "Allowed or denied scoped when using this permission.", + "allOf": [ + { + "$ref": "#/definitions/Scopes" + } + ] + }, + "platforms": { + "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", + "type": "object", + "properties": { + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "PermissionKind": { + "type": "string", + "oneOf": [ + { + "description": "Enables the activate command without any pre-configured scope.", + "type": "string", + "const": "allow-activate" + }, + { + "description": "Denies the activate command without any pre-configured scope.", + "type": "string", + "const": "deny-activate" + }, + { + "description": "Enables the add command without any pre-configured scope.", + "type": "string", + "const": "allow-add" + }, + { + "description": "Denies the add command without any pre-configured scope.", + "type": "string", + "const": "deny-add" + }, + { + "description": "Enables the apply command without any pre-configured scope.", + "type": "string", + "const": "allow-apply" + }, + { + "description": "Denies the apply command without any pre-configured scope.", + "type": "string", + "const": "deny-apply" + }, + { + "description": "Enables the calculate command without any pre-configured scope.", + "type": "string", + "const": "allow-calculate" + }, + { + "description": "Denies the calculate command without any pre-configured scope.", + "type": "string", + "const": "deny-calculate" + }, + { + "description": "Enables the check command without any pre-configured scope.", + "type": "string", + "const": "allow-check" + }, + { + "description": "Denies the check command without any pre-configured scope.", + "type": "string", + "const": "deny-check" + }, + { + "description": "Enables the checkout command without any pre-configured scope.", + "type": "string", + "const": "allow-checkout" + }, + { + "description": "Denies the checkout command without any pre-configured scope.", + "type": "string", + "const": "deny-checkout" + }, + { + "description": "Enables the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-add" + }, + { + "description": "Denies the cmd_add command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-add" + }, + { + "description": "Enables the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-checkout" + }, + { + "description": "Denies the cmd_checkout command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-checkout" + }, + { + "description": "Enables the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-commit" + }, + { + "description": "Denies the cmd_commit command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-commit" + }, + { + "description": "Enables the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-init" + }, + { + "description": "Denies the cmd_init command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-init" + }, + { + "description": "Enables the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-log" + }, + { + "description": "Denies the cmd_log command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-log" + }, + { + "description": "Enables the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "allow-cmd-status" + }, + { + "description": "Denies the cmd_status command without any pre-configured scope.", + "type": "string", + "const": "deny-cmd-status" + }, + { + "description": "Enables the commit command without any pre-configured scope.", + "type": "string", + "const": "allow-commit" + }, + { + "description": "Denies the commit command without any pre-configured scope.", + "type": "string", + "const": "deny-commit" + }, + { + "description": "Enables the init command without any pre-configured scope.", + "type": "string", + "const": "allow-init" + }, + { + "description": "Denies the init command without any pre-configured scope.", + "type": "string", + "const": "deny-init" + }, + { + "description": "Enables the init_repo command without any pre-configured scope.", + "type": "string", + "const": "allow-init-repo" + }, + { + "description": "Denies the init_repo command without any pre-configured scope.", + "type": "string", + "const": "deny-init-repo" + }, + { + "description": "Enables the initialize command without any pre-configured scope.", + "type": "string", + "const": "allow-initialize" + }, + { + "description": "Denies the initialize command without any pre-configured scope.", + "type": "string", + "const": "deny-initialize" + }, + { + "description": "Enables the log command without any pre-configured scope.", + "type": "string", + "const": "allow-log" + }, + { + "description": "Denies the log command without any pre-configured scope.", + "type": "string", + "const": "deny-log" + }, + { + "description": "Enables the status command without any pre-configured scope.", + "type": "string", + "const": "allow-status" + }, + { + "description": "Denies the status command without any pre-configured scope.", + "type": "string", + "const": "deny-status" + }, + { + "description": "Enables the sync command without any pre-configured scope.", + "type": "string", + "const": "allow-sync" + }, + { + "description": "Denies the sync command without any pre-configured scope.", + "type": "string", + "const": "deny-sync" + }, + { + "description": "Enables the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "allow-sync-fs" + }, + { + "description": "Denies the sync_fs command without any pre-configured scope.", + "type": "string", + "const": "deny-sync-fs" + }, + { + "description": "Enables the unstage command without any pre-configured scope.", + "type": "string", + "const": "allow-unstage" + }, + { + "description": "Denies the unstage command without any pre-configured scope.", + "type": "string", + "const": "deny-unstage" + }, + { + "description": "Default permissions for the plugin", + "type": "string", + "const": "default" + } + ] + } + } +} \ No newline at end of file diff --git a/src-tauri/yaak-sync/src/commands.rs b/src-tauri/yaak-sync/src/commands.rs new file mode 100644 index 00000000..255d9690 --- /dev/null +++ b/src-tauri/yaak-sync/src/commands.rs @@ -0,0 +1,13 @@ +use crate::error::Result; +use crate::sync::{apply_sync, calculate_sync, SyncOp}; +use tauri::{command, Runtime, WebviewWindow}; + +#[command] +pub async fn apply(window: WebviewWindow, workspace_id: &str) -> Result<()> { + apply_sync(&window, workspace_id).await +} + +#[command] +pub async fn calculate(window: WebviewWindow, workspace_id: &str) -> Result> { + calculate_sync(&window, workspace_id).await +} diff --git a/src-tauri/yaak-sync/src/error.rs b/src-tauri/yaak-sync/src/error.rs new file mode 100644 index 00000000..2e1db899 --- /dev/null +++ b/src-tauri/yaak-sync/src/error.rs @@ -0,0 +1,38 @@ +use serde::{Serialize, Serializer}; +use std::io; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Yaml error: {0}")] + YamlParseError(#[from] serde_yaml::Error), + + #[error("Yaml error: {0}")] + ModelError(#[from] yaak_models::error::Error), + + #[error("Unknown model: {0}")] + UnknownModel(String), + + #[error("Workspace not configured for sync: {0}")] + WorkspaceSyncNotConfigured(String), + + #[error("I/o error: {0}")] + IoError(#[from] io::Error), + + #[error("Yaml error: {0}")] + JsonParseError(#[from] serde_json::Error), + + #[error("Invalid sync file: {0}")] + InvalidSyncFile(String), +} + +impl Serialize for Error { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + serializer.serialize_str(self.to_string().as_ref()) + } +} + +pub type Result = std::result::Result; diff --git a/src-tauri/yaak-sync/src/lib.rs b/src-tauri/yaak-sync/src/lib.rs new file mode 100644 index 00000000..3388e446 --- /dev/null +++ b/src-tauri/yaak-sync/src/lib.rs @@ -0,0 +1,15 @@ +use crate::commands::{apply, calculate}; +use tauri::{ + generate_handler, + plugin::{Builder, TauriPlugin}, + Runtime, +}; + +mod commands; +mod error; +mod models; +mod sync; + +pub fn init() -> TauriPlugin { + Builder::new("yaak-sync").invoke_handler(generate_handler![calculate, apply]).build() +} diff --git a/src-tauri/yaak-sync/src/models.rs b/src-tauri/yaak-sync/src/models.rs new file mode 100644 index 00000000..93b77a92 --- /dev/null +++ b/src-tauri/yaak-sync/src/models.rs @@ -0,0 +1,109 @@ +use crate::error::Error::{InvalidSyncFile, UnknownModel}; +use crate::error::Result; +use chrono::NaiveDateTime; +use serde::{Deserialize, Serialize}; +use sha1::{Digest, Sha1}; +use std::fs; +use std::path::Path; +use ts_rs::TS; +use yaak_models::models::{AnyModel, Environment, Folder, GrpcRequest, HttpRequest, Workspace}; + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "snake_case", tag = "type")] +#[ts(export, export_to = "models.ts")] +pub enum SyncModel { + Workspace(Workspace), + Environment(Environment), + Folder(Folder), + HttpRequest(HttpRequest), + GrpcRequest(GrpcRequest), +} + +impl SyncModel { + pub fn from_file(file_path: &Path) -> Result, String)>> { + let content = match fs::read(file_path) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let mut hasher = Sha1::new(); + hasher.update(&content); + let checksum = hex::encode(hasher.finalize()); + + let ext = file_path.extension().unwrap_or_default(); + if ext == "yml" || ext == "yaml" { + Ok(Some((serde_yaml::from_slice(content.as_slice())?, content, checksum))) + } else if ext == "json" { + Ok(Some((serde_json::from_reader(content.as_slice())?, content, checksum))) + } else { + Err(InvalidSyncFile(file_path.to_str().unwrap().to_string())) + } + } + + pub fn to_file_contents(&self, rel_path: &Path) -> Result<(Vec, String)> { + let ext = rel_path.extension().unwrap_or_default(); + let content = if ext == "yaml" || ext == "yml" { + serde_yaml::to_string(self)? + } else { + serde_json::to_string(self)? + }; + + let mut hasher = Sha1::new(); + hasher.update(&content); + let checksum = hex::encode(hasher.finalize()); + + Ok((content.into_bytes(), checksum)) + } + + pub fn id(&self) -> String { + match self.clone() { + SyncModel::Workspace(m) => m.id, + SyncModel::Environment(m) => m.id, + SyncModel::Folder(m) => m.id, + SyncModel::HttpRequest(m) => m.id, + SyncModel::GrpcRequest(m) => m.id, + } + } + + pub fn workspace_id(&self) -> String { + match self.clone() { + SyncModel::Workspace(m) => m.id, + SyncModel::Environment(m) => m.workspace_id, + SyncModel::Folder(m) => m.workspace_id, + SyncModel::HttpRequest(m) => m.workspace_id, + SyncModel::GrpcRequest(m) => m.workspace_id, + } + } + + pub fn updated_at(&self) -> NaiveDateTime { + match self.clone() { + SyncModel::Workspace(m) => m.updated_at, + SyncModel::Environment(m) => m.updated_at, + SyncModel::Folder(m) => m.updated_at, + SyncModel::HttpRequest(m) => m.updated_at, + SyncModel::GrpcRequest(m) => m.updated_at, + } + } +} + +impl TryFrom for SyncModel { + type Error = crate::error::Error; + + fn try_from(value: AnyModel) -> Result { + let m = match value { + AnyModel::Environment(m) => SyncModel::Environment(m), + AnyModel::Folder(m) => SyncModel::Folder(m), + AnyModel::GrpcRequest(m) => SyncModel::GrpcRequest(m), + AnyModel::HttpRequest(m) => SyncModel::HttpRequest(m), + AnyModel::Workspace(m) => SyncModel::Workspace(m), + AnyModel::CookieJar(m) => return Err(UnknownModel(m.model)), + AnyModel::GrpcConnection(m) => return Err(UnknownModel(m.model)), + AnyModel::GrpcEvent(m) => return Err(UnknownModel(m.model)), + AnyModel::HttpResponse(m) => return Err(UnknownModel(m.model)), + AnyModel::Plugin(m) => return Err(UnknownModel(m.model)), + AnyModel::Settings(m) => return Err(UnknownModel(m.model)), + AnyModel::KeyValue(m) => return Err(UnknownModel(m.model)), + }; + Ok(m) + } +} diff --git a/src-tauri/yaak-sync/src/sync.rs b/src-tauri/yaak-sync/src/sync.rs new file mode 100644 index 00000000..74d7663a --- /dev/null +++ b/src-tauri/yaak-sync/src/sync.rs @@ -0,0 +1,542 @@ +use crate::error::Error::{InvalidSyncFile, WorkspaceSyncNotConfigured}; +use crate::error::Result; +use crate::models::SyncModel; +use chrono::Utc; +use log::{debug, warn}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::fs; +use std::fs::create_dir_all; +use std::path::{Path, PathBuf}; +use tauri::{Manager, Runtime, WebviewWindow}; +use ts_rs::TS; +use yaak_models::models::{SyncState, Workspace}; +use yaak_models::queries::{ + delete_environment, delete_folder, delete_grpc_request, delete_http_request, delete_sync_state, + delete_workspace, get_workspace, get_workspace_export_resources, + list_sync_states_for_workspace, upsert_environment, upsert_folder, upsert_grpc_request, + upsert_http_request, upsert_sync_state, upsert_workspace, UpdateSource, +}; + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase", tag = "type")] +#[ts(export, export_to = "sync.ts")] +pub(crate) enum SyncOp { + FsCreate { + model: SyncModel, + }, + FsUpdate { + model: SyncModel, + state: SyncState, + }, + FsDelete { + state: SyncState, + fs: Option, + }, + DbCreate { + fs: FsCandidate, + }, + DbUpdate { + state: SyncState, + fs: FsCandidate, + }, + DbDelete { + model: SyncModel, + state: SyncState, + }, +} + +impl Display for SyncOp { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str( + match self { + SyncOp::FsCreate { model } => format!("fs_create({})", model.id()), + SyncOp::FsUpdate { model, .. } => format!("fs_update({})", model.id()), + SyncOp::FsDelete { state, .. } => format!("fs_delete({})", state.model_id), + SyncOp::DbCreate { fs } => format!("db_create({})", fs.model.id()), + SyncOp::DbUpdate { fs, .. } => format!("db_update({})", fs.model.id()), + SyncOp::DbDelete { model, .. } => format!("db_delete({})", model.id()), + } + .as_str(), + ) + } +} + +#[derive(Debug, Clone)] +enum DbCandidate { + Added(SyncModel), + Modified(SyncModel, SyncState), + Deleted(SyncState), + Unmodified(SyncModel, SyncState), +} + +impl DbCandidate { + fn model_id(&self) -> String { + match &self { + DbCandidate::Added(m) => m.id(), + DbCandidate::Modified(m, _) => m.id(), + DbCandidate::Deleted(s) => s.model_id.clone(), + DbCandidate::Unmodified(m, _) => m.id(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase", tag = "type")] +#[ts(export, export_to = "sync.ts")] +pub(crate) struct FsCandidate { + model: SyncModel, + rel_path: PathBuf, + checksum: String, +} + +pub(crate) async fn calculate_sync( + window: &WebviewWindow, + workspace_id: &str, +) -> Result> { + let workspace = get_workspace(window, workspace_id).await?; + let db_candidates = get_db_candidates(window, &workspace).await?; + let fs_candidates = get_fs_candidates(&workspace)?; + let sync_ops = compute_sync_ops(db_candidates, fs_candidates); + + Ok(sync_ops) +} + +pub(crate) async fn apply_sync( + window: &WebviewWindow, + workspace_id: &str, +) -> Result<()> { + let workspace = get_workspace(window, workspace_id).await?; + let sync_ops = calculate_sync(window, workspace_id).await?; + + let sync_state_ops = apply_sync_ops(window, &workspace, sync_ops).await?; + let result = apply_sync_state_ops(window, &workspace, sync_state_ops).await; + + result +} + +async fn get_db_candidates( + mgr: &impl Manager, + workspace: &Workspace, +) -> Result> { + let workspace_id = workspace.id.as_str(); + let models = workspace_models(mgr, workspace).await; + let sync_dir = get_workspace_sync_dir(workspace)?; + let sync_states = list_sync_states_for_workspace(mgr, workspace_id, sync_dir).await?; + + // 1. Add candidates for models (created/modified/unmodified) + let mut candidates: Vec = models + .iter() + .map(|model| { + let existing_sync_state = sync_states.iter().find(|ss| ss.model_id == model.id()); + let existing_sync_state = match existing_sync_state { + Some(s) => s, + None => { + // No sync state yet, so model was just added + return DbCandidate::Added(model.to_owned()); + } + }; + + let updated_since_flush = model.updated_at() > existing_sync_state.flushed_at; + if updated_since_flush { + DbCandidate::Modified(model.to_owned(), existing_sync_state.to_owned()) + } else { + DbCandidate::Unmodified(model.to_owned(), existing_sync_state.to_owned()) + } + }) + .collect(); + + // 2. Add SyncState-only candidates (deleted) + candidates.extend(sync_states.iter().filter_map(|sync_state| { + let already_added = models.iter().find(|m| m.id() == sync_state.model_id).is_some(); + if already_added { + return None; + } + Some(DbCandidate::Deleted(sync_state.to_owned())) + })); + + Ok(candidates) +} + +fn get_fs_candidates(workspace: &Workspace) -> Result> { + let dir = match workspace.setting_sync_dir.clone() { + None => return Ok(Vec::new()), + Some(d) => d, + }; + + // Ensure the root directory exists + create_dir_all(dir.clone())?; + + let candidates = fs::read_dir(dir)? + .filter_map(|dir_entry| { + let dir_entry = dir_entry.ok()?; + if !dir_entry.file_type().ok()?.is_file() { + return None; + }; + + let path = dir_entry.path(); + let (model, _, checksum) = match SyncModel::from_file(&path) { + Ok(Some(m)) => m, + Ok(None) => return None, + Err(InvalidSyncFile(_)) => return None, + Err(e) => { + warn!("Failed to read sync file {e}"); + return None; + } + }; + + // Skip models belonging to different workspace + if model.workspace_id() != workspace.id.as_str() { + debug!("Skipping non-workspace file"); + return None; + } + + let rel_path = Path::new(&dir_entry.file_name()).to_path_buf(); + Some(FsCandidate { + rel_path, + model, + checksum, + }) + }) + .collect(); + + Ok(candidates) +} + +fn compute_sync_ops( + db_candidates: Vec, + fs_candidates: Vec, +) -> Vec { + let mut db_map: HashMap = HashMap::new(); + for c in db_candidates { + db_map.insert(c.model_id(), c); + } + + let mut fs_map: HashMap = HashMap::new(); + for c in fs_candidates { + fs_map.insert(c.model.id(), c); + } + + // Collect all keys from both maps for the OUTER JOIN + let keys: std::collections::HashSet<_> = db_map.keys().chain(fs_map.keys()).collect(); + + keys.into_iter() + .filter_map(|k| { + let op = match (db_map.get(k), fs_map.get(k)) { + (None, None) => return None, // Can never happen + (None, Some(fs)) => SyncOp::DbCreate { fs: fs.to_owned() }, + (Some(DbCandidate::Unmodified(model, sync_state)), None) => SyncOp::DbDelete { + model: model.to_owned(), + state: sync_state.to_owned(), + }, + (Some(DbCandidate::Modified(model, sync_state)), None) => SyncOp::FsUpdate { + model: model.to_owned(), + state: sync_state.to_owned(), + }, + (Some(DbCandidate::Added(model)), None) => SyncOp::FsCreate { + model: model.to_owned(), + }, + (Some(DbCandidate::Deleted(sync_state)), None) => { + // Already deleted on FS, but sending it so the SyncState gets dealt with + SyncOp::FsDelete { + state: sync_state.to_owned(), + fs: None, + } + } + (Some(DbCandidate::Unmodified(_, sync_state)), Some(fs_candidate)) => { + if sync_state.checksum == fs_candidate.checksum { + return None; + } else { + SyncOp::DbUpdate { + state: sync_state.to_owned(), + fs: fs_candidate.to_owned(), + } + } + } + (Some(DbCandidate::Modified(model, sync_state)), Some(fs_candidate)) => { + if sync_state.checksum == fs_candidate.checksum { + SyncOp::FsUpdate { + model: model.to_owned(), + state: sync_state.to_owned(), + } + } else if model.updated_at() < fs_candidate.model.updated_at() { + // CONFLICT! Write to DB if fs model is newer + SyncOp::DbUpdate { + state: sync_state.to_owned(), + fs: fs_candidate.to_owned(), + } + } else { + // CONFLICT! Write to FS if db model is newer + SyncOp::FsUpdate { + model: model.to_owned(), + state: sync_state.to_owned(), + } + } + } + (Some(DbCandidate::Added(model)), Some(_)) => { + // This would be super rare, so let's follow the user's intention + SyncOp::FsCreate { + model: model.to_owned(), + } + } + (Some(DbCandidate::Deleted(sync_state)), Some(fs_candidate)) => SyncOp::FsDelete { + state: sync_state.to_owned(), + fs: Some(fs_candidate.to_owned()), + }, + }; + Some(op) + }) + .collect() +} + +async fn workspace_models( + mgr: &impl Manager, + workspace: &Workspace, +) -> Vec { + let workspace_id = workspace.id.as_str(); + let resources = get_workspace_export_resources(mgr, vec![workspace_id]).await.resources; + + let mut sync_models = vec![SyncModel::Workspace(workspace.to_owned())]; + for m in resources.environments { + sync_models.push(SyncModel::Environment(m)); + } + for m in resources.folders { + sync_models.push(SyncModel::Folder(m)); + } + for m in resources.http_requests { + sync_models.push(SyncModel::HttpRequest(m)); + } + for m in resources.grpc_requests { + sync_models.push(SyncModel::GrpcRequest(m)); + } + + sync_models +} + +async fn apply_sync_ops( + window: &WebviewWindow, + workspace: &Workspace, + sync_ops: Vec, +) -> Result> { + if sync_ops.is_empty() { + return Ok(Vec::new()); + } + + debug!( + "Sync ops {}", + sync_ops.iter().map(|op| op.to_string()).collect::>().join(", ") + ); + let mut sync_state_ops = Vec::new(); + for op in sync_ops { + let op = apply_sync_op(window, workspace, &op).await?; + sync_state_ops.push(op); + } + Ok(sync_state_ops) +} + +#[derive(Debug)] +enum SyncStateOp { + Create { + model_id: String, + checksum: String, + rel_path: PathBuf, + }, + Update { + state: SyncState, + checksum: String, + rel_path: PathBuf, + }, + Delete { + state: SyncState, + }, +} + +/// Flush a DB model to the filesystem +async fn apply_sync_op( + window: &WebviewWindow, + workspace: &Workspace, + op: &SyncOp, +) -> Result { + let sync_state_op = match op { + SyncOp::FsCreate { model } => { + let rel_path = derive_model_filename(&model); + let abs_path = derive_full_model_path(workspace, &model)?; + let (content, checksum) = model.to_file_contents(&rel_path)?; + fs::write(&abs_path, content)?; + SyncStateOp::Create { + model_id: model.id(), + checksum, + rel_path, + } + } + SyncOp::FsUpdate { model, state } => { + let rel_path = derive_model_filename(&model); + let abs_path = derive_full_model_path(workspace, &model)?; + let (content, checksum) = model.to_file_contents(&rel_path)?; + fs::write(&abs_path, content)?; + SyncStateOp::Update { + state: state.to_owned(), + checksum, + rel_path, + } + } + SyncOp::FsDelete { + state, + fs: fs_candidate, + } => match fs_candidate { + None => SyncStateOp::Delete { + state: state.to_owned(), + }, + Some(fs_candidate) => { + let abs_path = derive_full_model_path(workspace, &fs_candidate.model)?; + fs::remove_file(&abs_path)?; + SyncStateOp::Delete { + state: state.to_owned(), + } + } + }, + SyncOp::DbCreate { fs } => { + upsert_model(window, &fs.model).await?; + SyncStateOp::Create { + model_id: fs.model.id(), + checksum: fs.checksum.to_owned(), + rel_path: fs.rel_path.to_owned(), + } + } + SyncOp::DbUpdate { state, fs } => { + upsert_model(window, &fs.model).await?; + SyncStateOp::Update { + state: state.to_owned(), + checksum: fs.checksum.to_owned(), + rel_path: fs.rel_path.to_owned(), + } + } + SyncOp::DbDelete { model, state } => { + delete_model(window, model).await?; + SyncStateOp::Delete { + state: state.to_owned(), + } + } + }; + + Ok(sync_state_op) +} +async fn apply_sync_state_ops( + window: &WebviewWindow, + workspace: &Workspace, + ops: Vec, +) -> Result<()> { + for op in ops { + apply_sync_state_op(window, workspace, op).await? + } + Ok(()) +} + +async fn apply_sync_state_op( + window: &WebviewWindow, + workspace: &Workspace, + op: SyncStateOp, +) -> Result<()> { + let dir_path = get_workspace_sync_dir(workspace)?; + match op { + SyncStateOp::Create { + checksum, + rel_path, + model_id, + } => { + let sync_state = SyncState { + workspace_id: workspace.to_owned().id, + model_id, + checksum, + sync_dir: dir_path.to_str().unwrap().to_string(), + rel_path: rel_path.to_str().unwrap().to_string(), + flushed_at: Utc::now().naive_utc(), + ..Default::default() + }; + upsert_sync_state(window, sync_state).await?; + } + SyncStateOp::Update { + state: sync_state, + checksum, + rel_path, + } => { + let sync_state = SyncState { + checksum, + sync_dir: dir_path.to_str().unwrap().to_string(), + rel_path: rel_path.to_str().unwrap().to_string(), + flushed_at: Utc::now().naive_utc(), + ..sync_state + }; + upsert_sync_state(window, sync_state).await?; + } + SyncStateOp::Delete { state } => { + delete_sync_state(window, state.id.as_str()).await?; + } + } + + Ok(()) +} + +fn get_workspace_sync_dir(workspace: &Workspace) -> Result { + let workspace_id = workspace.to_owned().id; + match workspace.setting_sync_dir.to_owned() { + Some(d) => Ok(Path::new(&d).to_path_buf()), + None => Err(WorkspaceSyncNotConfigured(workspace_id)), + } +} + +fn derive_full_model_path(workspace: &Workspace, m: &SyncModel) -> Result { + let dir = get_workspace_sync_dir(workspace)?; + Ok(dir.join(derive_model_filename(m))) +} + +fn derive_model_filename(m: &SyncModel) -> PathBuf { + let rel = format!("{}.yaml", m.id()); + let rel = Path::new(&rel).to_path_buf(); + + // Ensure parent dir exists + rel +} + +async fn upsert_model(window: &WebviewWindow, m: &SyncModel) -> Result<()> { + match m { + SyncModel::Workspace(m) => { + upsert_workspace(window, m.to_owned(), &UpdateSource::Sync).await?; + } + SyncModel::Environment(m) => { + upsert_environment(window, m.to_owned(), &UpdateSource::Sync).await?; + } + SyncModel::Folder(m) => { + upsert_folder(window, m.to_owned(), &UpdateSource::Sync).await?; + } + SyncModel::HttpRequest(m) => { + upsert_http_request(window, m.to_owned(), &UpdateSource::Sync).await?; + } + SyncModel::GrpcRequest(m) => { + upsert_grpc_request(window, m.to_owned(), &UpdateSource::Sync).await?; + } + }; + Ok(()) +} + +async fn delete_model(window: &WebviewWindow, model: &SyncModel) -> Result<()> { + match model { + SyncModel::Workspace(m) => { + delete_workspace(window, m.id.as_str(), &UpdateSource::Sync).await?; + } + SyncModel::Environment(m) => { + delete_environment(window, m.id.as_str(), &UpdateSource::Sync).await?; + } + SyncModel::Folder(m) => { + delete_folder(window, m.id.as_str(), &UpdateSource::Sync).await?; + } + SyncModel::HttpRequest(m) => { + delete_http_request(window, m.id.as_str(), &UpdateSource::Sync).await?; + } + SyncModel::GrpcRequest(m) => { + delete_grpc_request(window, m.id.as_str(), &UpdateSource::Sync).await?; + } + }; + Ok(()) +} diff --git a/src-tauri/yaak_templates/Cargo.toml b/src-tauri/yaak-templates/Cargo.toml similarity index 90% rename from src-tauri/yaak_templates/Cargo.toml rename to src-tauri/yaak-templates/Cargo.toml index 4e70f763..d74805fe 100644 --- a/src-tauri/yaak_templates/Cargo.toml +++ b/src-tauri/yaak-templates/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "yaak_templates" +name = "yaak-templates" version = "0.1.0" edition = "2021" publish = false diff --git a/src-tauri/yaak_templates/bindings/parser.ts b/src-tauri/yaak-templates/bindings/parser.ts similarity index 100% rename from src-tauri/yaak_templates/bindings/parser.ts rename to src-tauri/yaak-templates/bindings/parser.ts diff --git a/src-tauri/yaak_templates/index.ts b/src-tauri/yaak-templates/index.ts similarity index 100% rename from src-tauri/yaak_templates/index.ts rename to src-tauri/yaak-templates/index.ts diff --git a/src-tauri/yaak_templates/package.json b/src-tauri/yaak-templates/package.json similarity index 100% rename from src-tauri/yaak_templates/package.json rename to src-tauri/yaak-templates/package.json diff --git a/src-tauri/yaak_templates/src/format.rs b/src-tauri/yaak-templates/src/format.rs similarity index 100% rename from src-tauri/yaak_templates/src/format.rs rename to src-tauri/yaak-templates/src/format.rs diff --git a/src-tauri/yaak_templates/src/lib.rs b/src-tauri/yaak-templates/src/lib.rs similarity index 100% rename from src-tauri/yaak_templates/src/lib.rs rename to src-tauri/yaak-templates/src/lib.rs diff --git a/src-tauri/yaak_templates/src/parser.rs b/src-tauri/yaak-templates/src/parser.rs similarity index 100% rename from src-tauri/yaak_templates/src/parser.rs rename to src-tauri/yaak-templates/src/parser.rs diff --git a/src-tauri/yaak_templates/src/renderer.rs b/src-tauri/yaak-templates/src/renderer.rs similarity index 100% rename from src-tauri/yaak_templates/src/renderer.rs rename to src-tauri/yaak-templates/src/renderer.rs diff --git a/src-tauri/yaak_plugin_runtime/src/lib.rs b/src-tauri/yaak_plugin_runtime/src/lib.rs deleted file mode 100644 index 60f76772..00000000 --- a/src-tauri/yaak_plugin_runtime/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod error; -pub mod events; -pub mod manager; -mod nodejs; -pub mod plugin; -mod server; -pub mod plugin_handle; -mod util; diff --git a/src-web/components/CommandPalette.tsx b/src-web/components/CommandPaletteDialog.tsx similarity index 95% rename from src-web/components/CommandPalette.tsx rename to src-web/components/CommandPaletteDialog.tsx index 03b52546..3ea597ea 100644 --- a/src-web/components/CommandPalette.tsx +++ b/src-web/components/CommandPaletteDialog.tsx @@ -6,6 +6,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useActiveCookieJar } from '../hooks/useActiveCookieJar'; import { useActiveEnvironment } from '../hooks/useActiveEnvironment'; import { useActiveRequest } from '../hooks/useActiveRequest'; +import { useCommands } from '../hooks/useCommands'; import { useCreateEnvironment } from '../hooks/useCreateEnvironment'; import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest'; import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest'; @@ -53,21 +54,22 @@ type CommandPaletteItem = { const MAX_PER_GROUP = 8; -export function CommandPalette({ onClose }: { onClose: () => void }) { +export function CommandPaletteDialog({ onClose }: { onClose: () => void }) { const [command, setCommand] = useDebouncedState('', 150); const [selectedItemKey, setSelectedItemKey] = useState(null); const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment(); const httpRequestActions = useHttpRequestActions(); const workspaces = useWorkspaces(); const { subEnvironments } = useEnvironments(); + const createWorkspace = useCreateWorkspace(); const recentEnvironments = useRecentEnvironments(); const recentWorkspaces = useRecentWorkspaces(); const requests = useRequests(); const activeRequest = useActiveRequest(); const [recentRequests] = useRecentRequests(); const openWorkspace = useOpenWorkspace(); - const createWorkspace = useCreateWorkspace(); const createHttpRequest = useCreateHttpRequest(); + const { createFolder } = useCommands(); const [activeCookieJar] = useActiveCookieJar(); const createGrpcRequest = useCreateGrpcRequest(); const createEnvironment = useCreateEnvironment(); @@ -91,13 +93,18 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { { key: 'app.create', label: 'Create Workspace', - onSelect: createWorkspace.mutate, + onSelect: createWorkspace, }, { key: 'http_request.create', label: 'Create HTTP Request', onSelect: () => createHttpRequest.mutate({}), }, + { + key: 'folder.create', + label: 'Create Folder', + onSelect: () => createFolder.mutate({}), + }, { key: 'cookies.show', label: 'Show Cookies', @@ -183,9 +190,10 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { activeRequest, baseEnvironment, createEnvironment, + createFolder, createGrpcRequest, createHttpRequest, - createWorkspace.mutate, + createWorkspace, deleteRequest.mutate, dialog, httpRequestActions, @@ -230,9 +238,14 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { }, [subEnvironments, recentEnvironments]); const sortedWorkspaces = useMemo(() => { - const r = [...workspaces].sort((a, b) => { - const aRecentIndex = recentWorkspaces.indexOf(a.id); - const bRecentIndex = recentWorkspaces.indexOf(b.id); + if (recentWorkspaces == null) { + // Should never happen + return workspaces; + } + + const r = [...workspaces].sort((a, b) => { + const aRecentIndex = recentWorkspaces?.indexOf(a.id); + const bRecentIndex = recentWorkspaces?.indexOf(b.id); if (aRecentIndex >= 0 && bRecentIndex >= 0) { return aRecentIndex - bRecentIndex; @@ -309,7 +322,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { for (const w of sortedWorkspaces) { workspaceGroup.items.push({ key: `switch-workspace-${w.id}`, - label: w.id + ' - ' + w.name, + label: w.name, onSelect: () => openWorkspace.mutate({ workspaceId: w.id, inNewWindow: false }), }); } diff --git a/src-web/components/CreateWorkspaceDialog.tsx b/src-web/components/CreateWorkspaceDialog.tsx new file mode 100644 index 00000000..781e5fb4 --- /dev/null +++ b/src-web/components/CreateWorkspaceDialog.tsx @@ -0,0 +1,54 @@ +import { useState } from 'react'; +import { useCommands } from '../hooks/useCommands'; +import { Button } from './core/Button'; +import { PlainInput } from './core/PlainInput'; +import { VStack } from './core/Stacks'; +import { MarkdownEditor } from './MarkdownEditor'; +import { SelectFile } from './SelectFile'; + +interface Props { + hide: () => void; +} + +export function CreateWorkspaceDialog({ hide }: Props) { + const [name, setName] = useState(''); + const [description, setDescription] = useState(''); + const [settingSyncDir, setSettingSyncDir] = useState(null); + const { createWorkspace } = useCommands(); + + return ( + { + e.preventDefault(); + await createWorkspace.mutateAsync({ name, description, settingSyncDir }); + hide(); + }} + > + + + + +
+ setSettingSyncDir(filePath)} + /> +
+ +
+ ); +} diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx index b2b1a325..65fa99f4 100644 --- a/src-web/components/GlobalHooks.tsx +++ b/src-web/components/GlobalHooks.tsx @@ -1,6 +1,9 @@ import { emit } from '@tauri-apps/api/event'; -import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin'; -import { useEnsureActiveCookieJar, useSubscribeActiveCookieJarId } from '../hooks/useActiveCookieJar'; +import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugins'; +import { + useEnsureActiveCookieJar, + useSubscribeActiveCookieJarId, +} from '../hooks/useActiveCookieJar'; import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment'; import { useActiveRequest } from '../hooks/useActiveRequest'; import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId'; @@ -13,10 +16,10 @@ import { useHotKey } from '../hooks/useHotKey'; import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent'; import { useNotificationToast } from '../hooks/useNotificationToast'; import { usePrompt } from '../hooks/usePrompt'; -import {useRecentCookieJars, useSubscribeRecentCookieJars} from '../hooks/useRecentCookieJars'; -import {useRecentEnvironments, useSubscribeRecentEnvironments} from '../hooks/useRecentEnvironments'; +import { useSubscribeRecentCookieJars } from '../hooks/useRecentCookieJars'; +import { useSubscribeRecentEnvironments } from '../hooks/useRecentEnvironments'; import { useSubscribeRecentRequests } from '../hooks/useRecentRequests'; -import {useRecentWorkspaces, useSubscribeRecentWorkspaces} from '../hooks/useRecentWorkspaces'; +import { useSubscribeRecentWorkspaces } from '../hooks/useRecentWorkspaces'; import { useSyncFontSizeSetting } from '../hooks/useSyncFontSizeSetting'; import { useSyncModelStores } from '../hooks/useSyncModelStores'; import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels'; @@ -42,10 +45,6 @@ export function GlobalHooks() { useSubscribeRecentEnvironments(); useSubscribeRecentCookieJars(); - // Include here so they always update, even if no component references them - useRecentWorkspaces(); - useRecentEnvironments(); - useRecentCookieJars(); useSyncWorkspaceChildModels(); useSubscribeTemplateFunctions(); diff --git a/src-web/components/GrpcConnectionLayout.tsx b/src-web/components/GrpcConnectionLayout.tsx index c0d73726..32e4d7a1 100644 --- a/src-web/components/GrpcConnectionLayout.tsx +++ b/src-web/components/GrpcConnectionLayout.tsx @@ -120,7 +120,7 @@ export function GrpcConnectionLayout({ style }: Props) { ) : messages.length >= 0 ? ( ) : ( - + )} ) diff --git a/src-web/components/MarkdownEditor.tsx b/src-web/components/MarkdownEditor.tsx index 321de735..0017c906 100644 --- a/src-web/components/MarkdownEditor.tsx +++ b/src-web/components/MarkdownEditor.tsx @@ -64,7 +64,7 @@ export function MarkdownEditor({ defaultValue.length === 0 ? (

No description

) : ( - + ), - action: ( + action: ({ hide }) => ( diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index 2b27e18a..e41407ca 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -4,7 +4,7 @@ import type { EditorStateConfig, Extension } from '@codemirror/state'; import { Compartment, EditorState } from '@codemirror/state'; import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view'; import type { EnvironmentVariable } from '@yaakapp-internal/models'; -import type { TemplateFunction } from '@yaakapp-internal/plugin'; +import type { TemplateFunction } from '@yaakapp-internal/plugins'; import classNames from 'classnames'; import { EditorView } from 'codemirror'; import type { MutableRefObject, ReactNode } from 'react'; diff --git a/src-web/components/core/Icon.tsx b/src-web/components/core/Icon.tsx index bd497ea5..7e21a408 100644 --- a/src-web/components/core/Icon.tsx +++ b/src-web/components/core/Icon.tsx @@ -41,6 +41,8 @@ const icons = { file_code: lucide.FileCodeIcon, filter: lucide.FilterIcon, flask: lucide.FlaskConicalIcon, + folder: lucide.FolderIcon, + folder_sync: lucide.FolderSyncIcon, folder_input: lucide.FolderInputIcon, folder_output: lucide.FolderOutputIcon, git_branch: lucide.GitBranchIcon, diff --git a/src-web/components/core/Toast.tsx b/src-web/components/core/Toast.tsx index b237f61e..508ad9f7 100644 --- a/src-web/components/core/Toast.tsx +++ b/src-web/components/core/Toast.tsx @@ -1,4 +1,4 @@ -import type { ShowToastRequest } from '@yaakapp-internal/plugin'; +import type { ShowToastRequest } from '@yaakapp-internal/plugins'; import classNames from 'classnames'; import { motion } from 'framer-motion'; import type { ReactNode } from 'react'; @@ -15,7 +15,7 @@ export interface ToastProps { onClose: () => void; className?: string; timeout: number | null; - action?: ReactNode; + action?: (args: { hide: () => void }) => ReactNode; icon?: ShowToastRequest['icon']; color?: ShowToastRequest['color']; } @@ -59,15 +59,15 @@ export function Toast({ children, open, onClose, timeout, action, icon, color }: `x-theme-toast x-theme-toast--${color}`, 'pointer-events-auto overflow-hidden', 'relative pointer-events-auto bg-surface text-text rounded-lg', - 'border border-border shadow-lg max-w-[30rem]', + 'border border-border shadow-lg w-[25rem]', 'grid grid-cols-[1fr_auto]', )} > -
- {toastIcon && } - +
+ {toastIcon && } +
{children}
- {action} + {action?.({ hide: onClose })}
diff --git a/src-web/font-size.ts b/src-web/font-size.ts index 522b26a5..65765782 100644 --- a/src-web/font-size.ts +++ b/src-web/font-size.ts @@ -1,6 +1,6 @@ // Listen for settings changes, the re-compute theme import { listen } from '@tauri-apps/api/event'; -import type { ModelPayload } from './hooks/useSyncModelStores'; +import type { ModelPayload } from '@yaakapp-internal/models'; import { getSettings } from './lib/store'; function setFontSizeOnDocument(fontSize: number) { diff --git a/src-web/hooks/Prompt.tsx b/src-web/hooks/Prompt.tsx index e669cf6d..cffe2ae7 100644 --- a/src-web/hooks/Prompt.tsx +++ b/src-web/hooks/Prompt.tsx @@ -1,4 +1,4 @@ -import type { PromptTextRequest } from '@yaakapp-internal/plugin'; +import type { PromptTextRequest } from '@yaakapp-internal/plugins'; import type { FormEvent, ReactNode } from 'react'; import { useCallback, useState } from 'react'; import { Button } from '../components/core/Button'; diff --git a/src-web/hooks/useCommands.ts b/src-web/hooks/useCommands.ts new file mode 100644 index 00000000..12fad602 --- /dev/null +++ b/src-web/hooks/useCommands.ts @@ -0,0 +1,84 @@ +import { useNavigate } from '@tanstack/react-router'; +import type { Folder, Workspace } from '@yaakapp-internal/models'; +import { useMemo } from 'react'; +import { trackEvent } from '../lib/analytics'; +import { jotaiStore } from '../lib/jotai'; +import { invokeCmd } from '../lib/tauri'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; +import { createFastMutation } from './useFastMutation'; +import { foldersAtom } from './useFolders'; +import { usePrompt } from './usePrompt'; +import { updateModelList } from './useSyncModelStores'; +import { useToast } from './useToast'; +import { workspacesAtom } from './useWorkspaces'; + +function makeCommands({ + navigate, + prompt, +}: { + navigate: ReturnType; + prompt: ReturnType; + toast: ReturnType; +}) { + return { + createWorkspace: createFastMutation>({ + mutationKey: ['create_workspace'], + mutationFn: (patch) => invokeCmd('cmd_update_workspace', { workspace: patch }), + onSuccess: async (workspace) => { + // Optimistic update + jotaiStore.set(workspacesAtom, updateModelList(workspace)); + + await navigate({ + to: '/workspaces/$workspaceId', + params: { workspaceId: workspace.id }, + }); + }, + onSettled: () => trackEvent('workspace', 'create'), + }), + + createFolder: createFastMutation< + Folder | null, + void, + Partial> + >({ + mutationKey: ['create_folder'], + mutationFn: async (patch) => { + const workspaceId = getActiveWorkspaceId(); + if (workspaceId == null) { + throw new Error("Cannot create folder when there's no active workspace"); + } + + if (!patch.name) { + const name = await prompt({ + id: 'new-folder', + label: 'Name', + defaultValue: 'Folder', + title: 'New Folder', + confirmText: 'Create', + placeholder: 'Name', + }); + if (name == null) return null; + + patch.name = name; + } + + patch.sortPriority = patch.sortPriority || -Date.now(); + return invokeCmd('cmd_update_folder', { folder: { workspaceId, ...patch } }); + }, + onSuccess: async (folder) => { + if (folder == null) return; + + // Optimistic update + jotaiStore.set(foldersAtom, updateModelList(folder)); + }, + onSettled: () => trackEvent('folder', 'create'), + }), + } as const; +} + +export function useCommands() { + const navigate = useNavigate(); + const toast = useToast(); + const prompt = usePrompt(); + return useMemo(() => makeCommands({ navigate, toast, prompt }), [navigate, prompt, toast]); +} diff --git a/src-web/hooks/useCreateDropdownItems.tsx b/src-web/hooks/useCreateDropdownItems.tsx index ae8acab4..b757b6c9 100644 --- a/src-web/hooks/useCreateDropdownItems.tsx +++ b/src-web/hooks/useCreateDropdownItems.tsx @@ -4,7 +4,7 @@ import { Icon } from '../components/core/Icon'; import { generateId } from '../lib/generateId'; import { BODY_TYPE_GRAPHQL } from '../lib/model_util'; import { getActiveRequest } from './useActiveRequest'; -import { useCreateFolder } from './useCreateFolder'; +import {useCommands} from "./useCommands"; import { useCreateGrpcRequest } from './useCreateGrpcRequest'; import { useCreateHttpRequest } from './useCreateHttpRequest'; @@ -19,7 +19,7 @@ export function useCreateDropdownItems({ } = {}): () => DropdownItem[] { const { mutate: createHttpRequest } = useCreateHttpRequest(); const { mutate: createGrpcRequest } = useCreateGrpcRequest(); - const { mutate: createFolder } = useCreateFolder(); + const { createFolder } = useCommands(); return useCallback((): DropdownItem[] => { const folderId = @@ -62,7 +62,7 @@ export function useCreateDropdownItems({ key: 'create-folder', label: 'Folder', leftSlot: hideIcons ? undefined : , - onSelect: () => createFolder({ folderId }), + onSelect: () => createFolder.mutate({ folderId }), }, ]) as DropdownItem[]), ]; diff --git a/src-web/hooks/useCreateEnvironment.ts b/src-web/hooks/useCreateEnvironment.ts index 9639bd7f..d50d2814 100644 --- a/src-web/hooks/useCreateEnvironment.ts +++ b/src-web/hooks/useCreateEnvironment.ts @@ -15,7 +15,6 @@ export function useCreateEnvironment() { const setEnvironments = useSetAtom(environmentsAtom); return useFastMutation({ - toastyError: true, mutationKey: ['create_environment'], mutationFn: async (baseEnvironment) => { if (baseEnvironment == null) { diff --git a/src-web/hooks/useCreateFolder.ts b/src-web/hooks/useCreateFolder.ts deleted file mode 100644 index 0330e33e..00000000 --- a/src-web/hooks/useCreateFolder.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Folder } from '@yaakapp-internal/models'; -import { useSetAtom } from 'jotai'; -import { trackEvent } from '../lib/analytics'; -import { invokeCmd } from '../lib/tauri'; -import { getActiveWorkspaceId } from './useActiveWorkspace'; -import { useFastMutation } from './useFastMutation'; -import { foldersAtom } from './useFolders'; -import { usePrompt } from './usePrompt'; -import { updateModelList } from './useSyncModelStores'; - -export function useCreateFolder() { - const prompt = usePrompt(); - const setFolders = useSetAtom(foldersAtom); - - return useFastMutation< - Folder | null, - unknown, - Partial> - >({ - mutationKey: ['create_folder'], - mutationFn: async (patch) => { - const workspaceId = getActiveWorkspaceId(); - if (workspaceId == null) { - throw new Error("Cannot create folder when there's no active workspace"); - } - - if (!patch.name) { - const name = await prompt({ - id: 'new-folder', - label: 'Name', - defaultValue: 'Folder', - title: 'New Folder', - confirmText: 'Create', - placeholder: 'Name', - }); - if (name == null) return null; - - patch.name = name; - } - - patch.sortPriority = patch.sortPriority || -Date.now(); - return await invokeCmd('cmd_create_folder', { workspaceId, ...patch }); - }, - onSuccess: (folder) => { - if (folder == null) return; - - // Optimistic update - setFolders(updateModelList(folder)); - }, - onSettled: () => trackEvent('folder', 'create'), - }); -} diff --git a/src-web/hooks/useCreateWorkspace.ts b/src-web/hooks/useCreateWorkspace.ts deleted file mode 100644 index 7cf5024d..00000000 --- a/src-web/hooks/useCreateWorkspace.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { useNavigate } from '@tanstack/react-router'; -import type { Workspace } from '@yaakapp-internal/models'; -import { useSetAtom } from 'jotai/index'; -import { invokeCmd } from '../lib/tauri'; -import { useFastMutation } from './useFastMutation'; -import { usePrompt } from './usePrompt'; -import { updateModelList } from './useSyncModelStores'; -import { workspacesAtom } from './useWorkspaces'; - -export function useCreateWorkspace() { - const prompt = usePrompt(); - const setWorkspaces = useSetAtom(workspacesAtom); - const navigate = useNavigate(); - - return useFastMutation({ - mutationKey: ['create_workspace'], - mutationFn: async () => { - const name = await prompt({ - id: 'new-workspace', - label: 'Name', - defaultValue: 'My Workspace', - title: 'New Workspace', - placeholder: 'My Workspace', - confirmText: 'Create', - }); - if (name == null) { - return null; - } - return invokeCmd('cmd_create_workspace', { name }); - }, - onSuccess: async (workspace) => { - if (workspace == null) return; - - // Optimistic update - setWorkspaces(updateModelList(workspace)); - - navigate({ - to: '/workspaces/$workspaceId', - params: { workspaceId: workspace.id }, - }); - }, - }); -} diff --git a/src-web/hooks/useCreateWorkspace.tsx b/src-web/hooks/useCreateWorkspace.tsx new file mode 100644 index 00000000..a9e36816 --- /dev/null +++ b/src-web/hooks/useCreateWorkspace.tsx @@ -0,0 +1,16 @@ +import { useCallback } from 'react'; +import { CreateWorkspaceDialog } from '../components/CreateWorkspaceDialog'; +import { useDialog } from './useDialog'; + +export function useCreateWorkspace() { + const dialog = useDialog(); + + return useCallback(() => { + dialog.show({ + id: 'create-workspace', + title: 'Create Workspace', + size: 'md', + render: ({ hide }) => , + }); + }, [dialog]); +} diff --git a/src-web/hooks/useFastMutation.ts b/src-web/hooks/useFastMutation.ts index afdb025f..95e62ea9 100644 --- a/src-web/hooks/useFastMutation.ts +++ b/src-web/hooks/useFastMutation.ts @@ -1,59 +1,58 @@ import type { MutationKey } from '@tanstack/react-query'; -import { useCallback } from 'react'; -import { useToast } from './useToast'; +import { useMemo } from 'react'; -export function useFastMutation({ - mutationKey, - mutationFn, - onSuccess, - onError, - onSettled, - toastyError, -}: { +interface MutationOptions { mutationKey: MutationKey; mutationFn: (vars: TVariables) => Promise; onSettled?: () => void; onError?: (err: TError) => void; onSuccess?: (data: TData) => void; - toastyError?: boolean; -}) { - const toast = useToast(); - - const mutateAsync = useCallback( - async (variables: TVariables) => { - try { - const data = await mutationFn(variables); - onSuccess?.(data); - return data; - } catch (err: unknown) { - const e = err as TError; - console.log('Fast mutation error', mutationKey, e); - onError?.(e); - if (toastyError) { - toast.show({ - id: 'error-' + mutationKey.join('.'), - color: 'danger', - timeout: 8000, - message: String(e), - }); - } - } finally { - onSettled?.(); - } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - mutationKey, - ); - - const mutate = useCallback( - (variables: TVariables) => { - setTimeout(() => mutateAsync(variables)); - }, - [mutateAsync], - ); - - return { - mutate, - mutateAsync, - }; +} + +type CallbackMutationOptions = Omit< + MutationOptions, + 'mutationKey' | 'mutationFn' +>; + +export function createFastMutation( + defaultArgs: MutationOptions, +) { + const mutateAsync = async ( + variables: TVariables, + args?: CallbackMutationOptions, + ) => { + const { mutationKey, mutationFn, onSuccess, onError, onSettled } = { + ...defaultArgs, + ...args, + }; + try { + const data = await mutationFn(variables); + onSuccess?.(data); + return data; + } catch (err: unknown) { + const e = err as TError; + console.log('Fast mutation error', mutationKey, e); + onError?.(e); + } finally { + onSettled?.(); + } + }; + + const mutate = ( + variables: TVariables, + args?: CallbackMutationOptions, + ) => { + setTimeout(() => mutateAsync(variables, args)); + }; + + return { mutateAsync, mutate }; +} + +export function useFastMutation( + defaultArgs: MutationOptions, +) { + return useMemo(() => { + return createFastMutation(defaultArgs); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, defaultArgs.mutationKey); } diff --git a/src-web/hooks/useFilterResponse.ts b/src-web/hooks/useFilterResponse.ts index 090874a3..5f9b2968 100644 --- a/src-web/hooks/useFilterResponse.ts +++ b/src-web/hooks/useFilterResponse.ts @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import type { FilterResponse } from '@yaakapp-internal/plugin'; +import type { FilterResponse } from '@yaakapp-internal/plugins'; import { invokeCmd } from '../lib/tauri'; export function useFilterResponse({ diff --git a/src-web/hooks/useHotKey.ts b/src-web/hooks/useHotKey.ts index 0d43a8b1..a198b25f 100644 --- a/src-web/hooks/useHotKey.ts +++ b/src-web/hooks/useHotKey.ts @@ -7,9 +7,13 @@ import { useOsInfo } from './useOsInfo'; const HOLD_KEYS = ['Shift', 'Control', 'Command', 'Alt', 'Meta']; export type HotkeyAction = + | 'app.zoom_in' + | 'app.zoom_out' + | 'app.zoom_reset' + | 'command_palette.toggle' | 'environmentEditor.toggle' - | 'hotkeys.showHelp' | 'grpc_request.send' + | 'hotkeys.showHelp' | 'http_request.create' | 'http_request.duplicate' | 'http_request.send' @@ -18,13 +22,14 @@ export type HotkeyAction = | 'request_switcher.toggle' | 'settings.show' | 'sidebar.focus' - | 'urlBar.focus' - | 'command_palette.toggle' - | 'app.zoom_in' - | 'app.zoom_out' - | 'app.zoom_reset'; + | 'url_bar.focus' + | 'workspace_settings.show'; const hotkeys: Record = { + 'app.zoom_in': ['CmdCtrl+='], + 'app.zoom_out': ['CmdCtrl+-'], + 'app.zoom_reset': ['CmdCtrl+0'], + 'command_palette.toggle': ['CmdCtrl+k'], 'environmentEditor.toggle': ['CmdCtrl+Shift+e'], 'grpc_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'], 'hotkeys.showHelp': ['CmdCtrl+Shift+/'], @@ -36,14 +41,15 @@ const hotkeys: Record = { 'request_switcher.toggle': ['CmdCtrl+p'], 'settings.show': ['CmdCtrl+,'], 'sidebar.focus': ['CmdCtrl+b'], - 'urlBar.focus': ['CmdCtrl+l'], - 'command_palette.toggle': ['CmdCtrl+k'], - 'app.zoom_in': ['CmdCtrl+='], - 'app.zoom_out': ['CmdCtrl+-'], - 'app.zoom_reset': ['CmdCtrl+0'], + 'url_bar.focus': ['CmdCtrl+l'], + 'workspace_settings.show': ['CmdCtrl+Shift+,'], }; const hotkeyLabels: Record = { + 'app.zoom_in': 'Zoom In', + 'app.zoom_out': 'Zoom Out', + 'app.zoom_reset': 'Zoom to Actual Size', + 'command_palette.toggle': 'Toggle Command Palette', 'environmentEditor.toggle': 'Edit Environments', 'grpc_request.send': 'Send Message', 'hotkeys.showHelp': 'Show Keyboard Shortcuts', @@ -55,11 +61,8 @@ const hotkeyLabels: Record = { 'request_switcher.toggle': 'Toggle Request Switcher', 'settings.show': 'Open Settings', 'sidebar.focus': 'Focus or Toggle Sidebar', - 'urlBar.focus': 'Focus URL', - 'command_palette.toggle': 'Toggle Command Palette', - 'app.zoom_in': 'Zoom In', - 'app.zoom_out': 'Zoom Out', - 'app.zoom_reset': 'Zoom to Actual Size', + 'url_bar.focus': 'Focus URL', + 'workspace_settings.show': 'Open Workspace Settings', }; export const hotkeyActions: HotkeyAction[] = Object.keys(hotkeys) as (keyof typeof hotkeys)[]; @@ -165,7 +168,7 @@ export function useHotKeyLabel(action: HotkeyAction): string { export function useFormattedHotkey(action: HotkeyAction | null): string[] | null { const osInfo = useOsInfo(); - const trigger = action != null ? hotkeys[action]?.[0] ?? null : null; + const trigger = action != null ? (hotkeys[action]?.[0] ?? null) : null; if (trigger == null || osInfo == null) { return null; } diff --git a/src-web/hooks/useHttpRequestActions.ts b/src-web/hooks/useHttpRequestActions.ts index bb4ab85d..ec5a0dc8 100644 --- a/src-web/hooks/useHttpRequestActions.ts +++ b/src-web/hooks/useHttpRequestActions.ts @@ -4,7 +4,7 @@ import type { CallHttpRequestActionRequest, GetHttpRequestActionsResponse, HttpRequestAction, -} from '@yaakapp-internal/plugin'; +} from '@yaakapp-internal/plugins'; import { invokeCmd } from '../lib/tauri'; import { usePluginsKey } from './usePlugins'; import { useMemo } from 'react'; diff --git a/src-web/hooks/useKeyValue.ts b/src-web/hooks/useKeyValue.ts index 03da1902..f3cecdf5 100644 --- a/src-web/hooks/useKeyValue.ts +++ b/src-web/hooks/useKeyValue.ts @@ -8,7 +8,7 @@ import { buildKeyValueKey, extractKeyValueOrFallback, setKeyValue } from '../lib const DEFAULT_NAMESPACE = 'global'; -export const keyValuesAtom = atom([]); +export const keyValuesAtom = atom(null); export function keyValueQueryKey({ namespace = DEFAULT_NAMESPACE, @@ -32,7 +32,7 @@ export function useKeyValue const keyValues = useAtomValue(keyValuesAtom); const keyValue = keyValues?.find((kv) => buildKeyValueKey(kv.key) === buildKeyValueKey(key)) ?? null; - const value = extractKeyValueOrFallback(keyValue, fallback); + const value = keyValues == null ? null : extractKeyValueOrFallback(keyValue, fallback); const isLoading = keyValues == null; const { mutateAsync } = useMutation({ @@ -43,7 +43,7 @@ export function useKeyValue const set = useCallback( async (valueOrUpdate: ((v: T) => T) | T) => { if (typeof valueOrUpdate === 'function') { - const newV = valueOrUpdate(value); + const newV = valueOrUpdate(value ?? fallback); if (newV === value) return; await mutateAsync(newV); } else { diff --git a/src-web/hooks/useNotificationToast.tsx b/src-web/hooks/useNotificationToast.tsx index 722a4a08..419f5385 100644 --- a/src-web/hooks/useNotificationToast.tsx +++ b/src-web/hooks/useNotificationToast.tsx @@ -1,8 +1,8 @@ import { open } from '@tauri-apps/plugin-shell'; import { Button } from '../components/core/Button'; -import { useToast } from './useToast'; import { invokeCmd } from '../lib/tauri'; import { useListenToTauriEvent } from './useListenToTauriEvent'; +import { useToast } from './useToast'; export function useNotificationToast() { const toast = useToast(); @@ -29,14 +29,14 @@ export function useNotificationToast() { message: payload.message, color: 'custom', onClose: () => markRead(payload.id), - action: + action: ({ hide }) => actionLabel && actionUrl ? (