From dd9c4c4be292724a7d40990491d63f3607fa8ab2 Mon Sep 17 00:00:00 2001 From: Mateusz Russak Date: Mon, 9 Feb 2026 11:32:20 +0100 Subject: [PATCH 1/6] ci: trigger docker build from release workflow (#271) Fix GITHUB_TOKEN limitation: release.yml now calls docker.yml directly via workflow_call so Docker builds are triggered automatically on release. --- .github/workflows/docker.yml | 11 ++++++++++- .github/workflows/release.yml | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e336d26d..78c2a3ad 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,6 +4,12 @@ on: push: tags: - v* + workflow_call: + inputs: + version: + required: true + type: string + workflow_dispatch: permissions: contents: write @@ -73,6 +79,9 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=tag + type=raw,value=${{ inputs.version }},enable=${{ inputs.version != '' }} - name: Build and push Docker image id: push @@ -85,7 +94,7 @@ jobs: push: true platforms: linux/amd64,linux/arm64 build-args: | - APP_VERSION=${{ github.ref_name }} + APP_VERSION=${{ inputs.version || github.ref_name }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7daa14d9..b3baf315 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,8 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + outputs: + version: ${{ steps.version.outputs.result }} steps: - name: Extract version from labels @@ -47,3 +49,10 @@ jobs: }); core.info(`Created release ${version}`); + + docker: + needs: release + uses: ./.github/workflows/docker.yml + with: + version: ${{ needs.release.outputs.version }} + secrets: inherit From 32ee02352ddd60be6b1ba1300495ab419db829af Mon Sep 17 00:00:00 2001 From: Mateusz Date: Mon, 9 Feb 2026 17:51:56 +0100 Subject: [PATCH 2/6] feat(desktop): add Tauri v2 desktop app with SSE notifications --- .github/workflows/desktop.yml | 90 + app/src/js/core/index.ts | 2 + app/src/js/core/notifications.ts | 52 + deno/server/inter/http/mod.ts | 3 +- desktop/.env.example | 2 + desktop/.gitignore | 2 + desktop/package.json | 10 + desktop/src-tauri/Cargo.lock | 5650 +++++++++++++++++ desktop/src-tauri/Cargo.toml | 23 + desktop/src-tauri/build.rs | 3 + desktop/src-tauri/capabilities/default.json | 20 + .../src-tauri/gen/schemas/acl-manifests.json | 1 + .../src-tauri/gen/schemas/capabilities.json | 1 + .../src-tauri/gen/schemas/desktop-schema.json | 2658 ++++++++ .../src-tauri/gen/schemas/linux-schema.json | 2658 ++++++++ desktop/src-tauri/icons/128x128.png | Bin 0 -> 3115 bytes desktop/src-tauri/icons/128x128@2x.png | Bin 0 -> 7953 bytes desktop/src-tauri/icons/32x32.png | Bin 0 -> 921 bytes desktop/src-tauri/icons/icon.ico | Bin 0 -> 59329 bytes desktop/src-tauri/icons/icon.png | Bin 0 -> 7966 bytes desktop/src-tauri/src/credentials.rs | 70 + desktop/src-tauri/src/lib.rs | 92 + desktop/src-tauri/src/main.rs | 6 + desktop/src-tauri/src/notifications.rs | 306 + desktop/src-tauri/src/tray.rs | 41 + desktop/src-tauri/tauri.conf.json | 50 + desktop/src/index.html | 115 + docs/adr/015-tauri-desktop-app.md | 47 + docs/adr/README.md | 1 + docs/desktop-app-plan.md | 159 + docs/desktop-app.md | 204 + 31 files changed, 12265 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/desktop.yml create mode 100644 desktop/.env.example create mode 100644 desktop/.gitignore create mode 100644 desktop/package.json create mode 100644 desktop/src-tauri/Cargo.lock create mode 100644 desktop/src-tauri/Cargo.toml create mode 100644 desktop/src-tauri/build.rs create mode 100644 desktop/src-tauri/capabilities/default.json create mode 100644 desktop/src-tauri/gen/schemas/acl-manifests.json create mode 100644 desktop/src-tauri/gen/schemas/capabilities.json create mode 100644 desktop/src-tauri/gen/schemas/desktop-schema.json create mode 100644 desktop/src-tauri/gen/schemas/linux-schema.json create mode 100644 desktop/src-tauri/icons/128x128.png create mode 100644 desktop/src-tauri/icons/128x128@2x.png create mode 100644 desktop/src-tauri/icons/32x32.png create mode 100644 desktop/src-tauri/icons/icon.ico create mode 100644 desktop/src-tauri/icons/icon.png create mode 100644 desktop/src-tauri/src/credentials.rs create mode 100644 desktop/src-tauri/src/lib.rs create mode 100644 desktop/src-tauri/src/main.rs create mode 100644 desktop/src-tauri/src/notifications.rs create mode 100644 desktop/src-tauri/src/tray.rs create mode 100644 desktop/src-tauri/tauri.conf.json create mode 100644 desktop/src/index.html create mode 100644 docs/adr/015-tauri-desktop-app.md create mode 100644 docs/desktop-app-plan.md create mode 100644 docs/desktop-app.md diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml new file mode 100644 index 00000000..ea012398 --- /dev/null +++ b/.github/workflows/desktop.yml @@ -0,0 +1,90 @@ +name: Build Desktop App + +on: + pull_request: + branches: [main, dev] + paths: + - 'desktop/**' + - '.github/workflows/desktop.yml' + push: + branches: [dev] + paths: + - 'desktop/**' + - '.github/workflows/desktop.yml' + workflow_dispatch: + release: + types: [published] + +permissions: + contents: write + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - platform: ubuntu-22.04 + target: x86_64-unknown-linux-gnu + - platform: macos-latest + target: aarch64-apple-darwin + - platform: macos-latest + target: x86_64-apple-darwin + - platform: windows-latest + target: x86_64-pc-windows-msvc + + runs-on: ${{ matrix.platform }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Rust cache + uses: swatinem/rust-cache@v2 + with: + workspaces: desktop/src-tauri -> target + + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf \ + libssl-dev + + - name: Install Tauri CLI + run: cargo install tauri-cli --version "^2" + + - name: Build desktop app + working-directory: desktop + run: cargo tauri build --target ${{ matrix.target }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: quack-desktop-${{ matrix.target }} + path: | + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.deb + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.AppImage + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.dmg + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.msi + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.exe + + - name: Upload to GitHub Release + if: github.event_name == 'release' + uses: softprops/action-gh-release@v2 + with: + files: | + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.deb + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.AppImage + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.dmg + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.msi + desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.exe diff --git a/app/src/js/core/index.ts b/app/src/js/core/index.ts index d5f3887b..9dd32d25 100644 --- a/app/src/js/core/index.ts +++ b/app/src/js/core/index.ts @@ -1,9 +1,11 @@ import { AppModel } from "./models/app.ts"; import { client } from "./client.ts"; +import { stopTauriNotifications } from "./notifications.ts"; export * from "./client.ts"; export const app = new AppModel(); client.on2("auth:logout", async () => { + await stopTauriNotifications(); await app.dispose(); window.location.reload(); }); diff --git a/app/src/js/core/notifications.ts b/app/src/js/core/notifications.ts index 91421127..604f0873 100644 --- a/app/src/js/core/notifications.ts +++ b/app/src/js/core/notifications.ts @@ -2,7 +2,23 @@ import { client } from "../core/index.ts"; import { OutgoingUserPushSubscribe } from "../core/types.ts"; import type { AppModel } from "../core/models/app.ts"; +declare global { + interface Window { + __TAURI__?: unknown; + __TAURI_INTERNALS__?: { + invoke: (cmd: string, args?: Record) => Promise; + }; + } +} + +const isTauri = () => typeof window.__TAURI_INTERNALS__ !== "undefined"; + export const initNotifications = async (app: AppModel) => { + if (isTauri()) { + await initTauriNotifications(app); + return; + } + if ("serviceWorker" in navigator) { navigator.serviceWorker.addEventListener("message", ({ data }) => { if (data.type) { @@ -21,6 +37,42 @@ export const initNotifications = async (app: AppModel) => { } }; +const initTauriNotifications = async (_app: AppModel) => { + const invoke = window.__TAURI_INTERNALS__!.invoke; + + const serverUrl = window.location.origin; + const authToken = client.api.token; + const userId = client.api.userId; + + if (!authToken || !userId) { + console.warn("Tauri notifications: missing auth token or user ID"); + return; + } + + try { + await invoke("start_notification_service", { + serverUrl, + authToken, + userId, + }); + console.log("Tauri notification service started"); + } catch (e) { + console.error("Failed to start Tauri notification service:", e); + } +}; + +export const stopTauriNotifications = async () => { + if (!isTauri()) return; + + try { + const invoke = window.__TAURI_INTERNALS__!.invoke; + await invoke("stop_notification_service"); + console.log("Tauri notification service stopped"); + } catch (e) { + console.error("Failed to stop Tauri notification service:", e); + } +}; + const register = async (app: AppModel, retry = false) => navigator.serviceWorker.getRegistration("/") .then((registration) => { diff --git a/deno/server/inter/http/mod.ts b/deno/server/inter/http/mod.ts index 5a5a2ba9..2a2878d3 100644 --- a/deno/server/inter/http/mod.ts +++ b/deno/server/inter/http/mod.ts @@ -63,7 +63,8 @@ export class HttpInterface extends Planigale { this.use("/api/messages", messages(core)); this.use("/api/read-receipts", readReceipt(core)); this.use("/api/interactions", interactions(core)); - this.use("/api/mobile", mobile(core)); + this.use("/api/notifications", mobile(core)); + this.use("/api/mobile", mobile(core)); // legacy alias this.use("/api/channels", channels(core)); this.use("/api/channels/:channelId/messages", channelMessages(core)); diff --git a/desktop/.env.example b/desktop/.env.example new file mode 100644 index 00000000..1d5c1504 --- /dev/null +++ b/desktop/.env.example @@ -0,0 +1,2 @@ +# Quack server URL (used during development) +QUACK_SERVER_URL=https://your-quack-server.com diff --git a/desktop/.gitignore b/desktop/.gitignore new file mode 100644 index 00000000..e074ce5c --- /dev/null +++ b/desktop/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +src-tauri/target/ diff --git a/desktop/package.json b/desktop/package.json new file mode 100644 index 00000000..ba266adb --- /dev/null +++ b/desktop/package.json @@ -0,0 +1,10 @@ +{ + "name": "@quack/desktop", + "version": "0.1.0", + "private": true, + "scripts": { + "tauri": "cargo tauri", + "dev": "cargo tauri dev", + "build": "cargo tauri build" + } +} diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock new file mode 100644 index 00000000..13cfffa8 --- /dev/null +++ b/desktop/src-tauri/Cargo.lock @@ -0,0 +1,5650 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "async-signal" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto-launch" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471" +dependencies = [ + "dirs 4.0.0", + "thiserror 1.0.69", + "winreg 0.10.1", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.10.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.11+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.29.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "matches", + "phf 0.10.1", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.114", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users 0.4.6", + "winapi", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.10.0", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.9.11+spec-1.1.0", + "vswhom", + "winreg 0.55.0", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.10.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +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-error", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.13.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever", + "match_token", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.10.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kuchikiki" +version = "0.8.8-speedreader" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 2.13.0", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags 2.10.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "mac-notification-sys" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fd3f75411f4725061682ed91f131946e912859d0044d39c4ec0aac818d7621" +dependencies = [ + "cc", + "objc2", + "objc2-foundation", + "time", +] + +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "muda" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 2.0.18", + "windows-sys 0.60.2", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.10.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "notify-rust" +version = "4.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21af20a1b50be5ac5861f74af1a863da53a11c38684d9818d82f1c42f7fdc6c2" +dependencies = [ + "futures-lite", + "log", + "mac-notification-sys", + "serde", + "tauri-winrt-notification", + "zbus", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.10.0", + "block2", + "libc", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.10.0", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-javascript-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" +dependencies = [ + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.10.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-javascript-core", + "objc2-security", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.10.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared 0.8.0", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plist" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +dependencies = [ + "base64 0.22.1", + "indexmap 2.13.0", + "quick-xml 0.38.4", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.10+spec-1.0.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quack-desktop" +version = "0.1.0" +dependencies = [ + "futures-util", + "log", + "reqwest 0.12.28", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-autostart", + "tauri-plugin-notification", + "tauri-plugin-store", + "tokio", +] + +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.114", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "servo_arc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.34.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" +dependencies = [ + "bitflags 2.10.0", + "block2", + "core-foundation 0.10.1", + "core-graphics", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463ae8677aa6d0f063a900b9c41ecd4ac2b7ca82f0b058cc4491540e55b20129" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs 6.0.0", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest 0.13.2", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.18", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca7bd893329425df750813e95bd2b643d5369d929438da96d5bbb7cc2c918f74" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs 6.0.0", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml 0.9.11+spec-1.1.0", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac423e5859d9f9ccdd32e3cf6a5866a15bedbf25aa6630bcb2acde9468f6ae3" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.114", + "tauri-utils", + "thiserror 2.0.18", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6a1bd2861ff0c8766b1d38b32a6a410f6dc6532d4ef534c47cfb2236092f59" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.114", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692a77abd8b8773e107a42ec0e05b767b8d2b7ece76ab36c6c3947e34df9f53f" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "toml 0.9.11+spec-1.1.0", + "walkdir", +] + +[[package]] +name = "tauri-plugin-autostart" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459383cebc193cdd03d1ba4acc40f2c408a7abce419d64bdcd2d745bc2886f70" +dependencies = [ + "auto-launch", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", +] + +[[package]] +name = "tauri-plugin-notification" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fc2c5ff41105bd1f7242d8201fdf3efd70749b82fa013a17f2126357d194cc" +dependencies = [ + "log", + "notify-rust", + "rand 0.9.2", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "time", + "url", +] + +[[package]] +name = "tauri-plugin-store" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca1a8ff83c269b115e98726ffc13f9e548a10161544a92ad121d6d0a96e16ea" +dependencies = [ + "dunce", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "tauri-runtime" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b885ffeac82b00f1f6fd292b6e5aabfa7435d537cef57d11e38a489956535651" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5204682391625e867d16584fedc83fc292fb998814c9f7918605c789cd876314" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcd169fccdff05eff2c1033210b9b94acd07a47e6fa9a3431cf09cfd4f01c87e" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever", + "http", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 0.9.11+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" +dependencies = [ + "dunce", + "embed-resource", + "toml 0.9.11+spec-1.1.0", +] + +[[package]] +name = "tauri-winrt-notification" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" +dependencies = [ + "quick-xml 0.37.5", + "thiserror 2.0.18", + "windows", + "windows-version", +] + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.14", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow 0.7.14", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow 0.7.14", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.10.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +dependencies = [ + "crossbeam-channel", + "dirs 6.0.0", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 2.0.18", + "windows-sys 0.60.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wry" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed1a195b0375491dd15a7066a10251be217ce743cf4bbbbdcf5391d6473bee0" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs 6.0.0", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfeff997a0aaa3eb20c4652baf788d2dfa6d2839a0ead0b3ff69ce2f9c4bdd1" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 0.7.14", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bbd5a90dbe8feee5b13def448427ae314ccd26a49cac47905cafefb9ff846f1" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +dependencies = [ + "serde", + "winnow 0.7.14", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zmij" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" + +[[package]] +name = "zvariant" +version = "5.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b64ef4f40c7951337ddc7023dd03528a57a3ce3408ee9da5e948bd29b232c4" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 0.7.14", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "484d5d975eb7afb52cc6b929c13d3719a20ad650fea4120e6310de3fc55e415c" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.114", + "winnow 0.7.14", +] diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml new file mode 100644 index 00000000..eee41235 --- /dev/null +++ b/desktop/src-tauri/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "quack-desktop" +version = "0.1.0" +edition = "2021" + +[lib] +name = "quack_desktop_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = ["tray-icon"] } +tauri-plugin-notification = "2" +tauri-plugin-autostart = "2" +tauri-plugin-store = "2" +reqwest = { version = "0.12", features = ["stream"] } +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +futures-util = "0.3" +log = "0.4" diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs new file mode 100644 index 00000000..d860e1e6 --- /dev/null +++ b/desktop/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/desktop/src-tauri/capabilities/default.json b/desktop/src-tauri/capabilities/default.json new file mode 100644 index 00000000..0d9d48e3 --- /dev/null +++ b/desktop/src-tauri/capabilities/default.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://raw.githubusercontent.com/niccolocase/niccolocase/main/packages/tauri/src/api/capability.schema.json", + "identifier": "default", + "description": "Default capabilities for the Quack desktop app", + "windows": ["main"], + "permissions": [ + "core:default", + "core:window:default", + "core:window:allow-close", + "core:window:allow-show", + "core:window:allow-hide", + "core:window:allow-set-focus", + "notification:default", + "notification:allow-notify", + "notification:allow-is-permission-granted", + "notification:allow-request-permission", + "store:default", + "autostart:default" + ] +} diff --git a/desktop/src-tauri/gen/schemas/acl-manifests.json b/desktop/src-tauri/gen/schemas/acl-manifests.json new file mode 100644 index 00000000..21773138 --- /dev/null +++ b/desktop/src-tauri/gen/schemas/acl-manifests.json @@ -0,0 +1 @@ +{"autostart":{"default_permission":{"identifier":"default","description":"This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n","permissions":["allow-enable","allow-disable","allow-is-enabled"]},"permissions":{"allow-disable":{"identifier":"allow-disable","description":"Enables the disable command without any pre-configured scope.","commands":{"allow":["disable"],"deny":[]}},"allow-enable":{"identifier":"allow-enable","description":"Enables the enable command without any pre-configured scope.","commands":{"allow":["enable"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"deny-disable":{"identifier":"deny-disable","description":"Denies the disable command without any pre-configured scope.","commands":{"allow":[],"deny":["disable"]}},"deny-enable":{"identifier":"deny-enable","description":"Denies the enable command without any pre-configured scope.","commands":{"allow":[],"deny":["enable"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}}},"permission_sets":{},"global_scope_schema":null},"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-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-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-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-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"notification":{"default_permission":{"identifier":"default","description":"This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n","permissions":["allow-is-permission-granted","allow-request-permission","allow-notify","allow-register-action-types","allow-register-listener","allow-cancel","allow-get-pending","allow-remove-active","allow-get-active","allow-check-permissions","allow-show","allow-batch","allow-list-channels","allow-delete-channel","allow-create-channel","allow-permission-state"]},"permissions":{"allow-batch":{"identifier":"allow-batch","description":"Enables the batch command without any pre-configured scope.","commands":{"allow":["batch"],"deny":[]}},"allow-cancel":{"identifier":"allow-cancel","description":"Enables the cancel command without any pre-configured scope.","commands":{"allow":["cancel"],"deny":[]}},"allow-check-permissions":{"identifier":"allow-check-permissions","description":"Enables the check_permissions command without any pre-configured scope.","commands":{"allow":["check_permissions"],"deny":[]}},"allow-create-channel":{"identifier":"allow-create-channel","description":"Enables the create_channel command without any pre-configured scope.","commands":{"allow":["create_channel"],"deny":[]}},"allow-delete-channel":{"identifier":"allow-delete-channel","description":"Enables the delete_channel command without any pre-configured scope.","commands":{"allow":["delete_channel"],"deny":[]}},"allow-get-active":{"identifier":"allow-get-active","description":"Enables the get_active command without any pre-configured scope.","commands":{"allow":["get_active"],"deny":[]}},"allow-get-pending":{"identifier":"allow-get-pending","description":"Enables the get_pending command without any pre-configured scope.","commands":{"allow":["get_pending"],"deny":[]}},"allow-is-permission-granted":{"identifier":"allow-is-permission-granted","description":"Enables the is_permission_granted command without any pre-configured scope.","commands":{"allow":["is_permission_granted"],"deny":[]}},"allow-list-channels":{"identifier":"allow-list-channels","description":"Enables the list_channels command without any pre-configured scope.","commands":{"allow":["list_channels"],"deny":[]}},"allow-notify":{"identifier":"allow-notify","description":"Enables the notify command without any pre-configured scope.","commands":{"allow":["notify"],"deny":[]}},"allow-permission-state":{"identifier":"allow-permission-state","description":"Enables the permission_state command without any pre-configured scope.","commands":{"allow":["permission_state"],"deny":[]}},"allow-register-action-types":{"identifier":"allow-register-action-types","description":"Enables the register_action_types command without any pre-configured scope.","commands":{"allow":["register_action_types"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-active":{"identifier":"allow-remove-active","description":"Enables the remove_active command without any pre-configured scope.","commands":{"allow":["remove_active"],"deny":[]}},"allow-request-permission":{"identifier":"allow-request-permission","description":"Enables the request_permission command without any pre-configured scope.","commands":{"allow":["request_permission"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"deny-batch":{"identifier":"deny-batch","description":"Denies the batch command without any pre-configured scope.","commands":{"allow":[],"deny":["batch"]}},"deny-cancel":{"identifier":"deny-cancel","description":"Denies the cancel command without any pre-configured scope.","commands":{"allow":[],"deny":["cancel"]}},"deny-check-permissions":{"identifier":"deny-check-permissions","description":"Denies the check_permissions command without any pre-configured scope.","commands":{"allow":[],"deny":["check_permissions"]}},"deny-create-channel":{"identifier":"deny-create-channel","description":"Denies the create_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["create_channel"]}},"deny-delete-channel":{"identifier":"deny-delete-channel","description":"Denies the delete_channel command without any pre-configured scope.","commands":{"allow":[],"deny":["delete_channel"]}},"deny-get-active":{"identifier":"deny-get-active","description":"Denies the get_active command without any pre-configured scope.","commands":{"allow":[],"deny":["get_active"]}},"deny-get-pending":{"identifier":"deny-get-pending","description":"Denies the get_pending command without any pre-configured scope.","commands":{"allow":[],"deny":["get_pending"]}},"deny-is-permission-granted":{"identifier":"deny-is-permission-granted","description":"Denies the is_permission_granted command without any pre-configured scope.","commands":{"allow":[],"deny":["is_permission_granted"]}},"deny-list-channels":{"identifier":"deny-list-channels","description":"Denies the list_channels command without any pre-configured scope.","commands":{"allow":[],"deny":["list_channels"]}},"deny-notify":{"identifier":"deny-notify","description":"Denies the notify command without any pre-configured scope.","commands":{"allow":[],"deny":["notify"]}},"deny-permission-state":{"identifier":"deny-permission-state","description":"Denies the permission_state command without any pre-configured scope.","commands":{"allow":[],"deny":["permission_state"]}},"deny-register-action-types":{"identifier":"deny-register-action-types","description":"Denies the register_action_types command without any pre-configured scope.","commands":{"allow":[],"deny":["register_action_types"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-active":{"identifier":"deny-remove-active","description":"Denies the remove_active command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_active"]}},"deny-request-permission":{"identifier":"deny-request-permission","description":"Denies the request_permission command without any pre-configured scope.","commands":{"allow":[],"deny":["request_permission"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}}},"permission_sets":{},"global_scope_schema":null},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-load","allow-get-store","allow-set","allow-get","allow-has","allow-delete","allow-clear","allow-reset","allow-keys","allow-values","allow-entries","allow-length","allow-reload","allow-save"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-get-store":{"identifier":"allow-get-store","description":"Enables the get_store command without any pre-configured scope.","commands":{"allow":["get_store"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reload":{"identifier":"allow-reload","description":"Enables the reload command without any pre-configured scope.","commands":{"allow":["reload"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-get-store":{"identifier":"deny-get-store","description":"Denies the get_store command without any pre-configured scope.","commands":{"allow":[],"deny":["get_store"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reload":{"identifier":"deny-reload","description":"Denies the reload command without any pre-configured scope.","commands":{"allow":[],"deny":["reload"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/desktop/src-tauri/gen/schemas/capabilities.json b/desktop/src-tauri/gen/schemas/capabilities.json new file mode 100644 index 00000000..f07c99d2 --- /dev/null +++ b/desktop/src-tauri/gen/schemas/capabilities.json @@ -0,0 +1 @@ +{"default":{"identifier":"default","description":"Default capabilities for the Quack desktop app","local":true,"windows":["main"],"permissions":["core:default","core:window:default","core:window:allow-close","core:window:allow-show","core:window:allow-hide","core:window:allow-set-focus","notification:default","notification:allow-notify","notification:allow-is-permission-granted","notification:allow-request-permission","store:default","autostart:default"]}} \ No newline at end of file diff --git a/desktop/src-tauri/gen/schemas/desktop-schema.json b/desktop/src-tauri/gen/schemas/desktop-schema.json new file mode 100644 index 00000000..fb8b111d --- /dev/null +++ b/desktop/src-tauri/gen/schemas/desktop-schema.json @@ -0,0 +1,2658 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "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" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`", + "type": "string", + "const": "autostart:default", + "markdownDescription": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`" + }, + { + "description": "Enables the disable command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-disable", + "markdownDescription": "Enables the disable command without any pre-configured scope." + }, + { + "description": "Enables the enable command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-enable", + "markdownDescription": "Enables the enable command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the disable command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-disable", + "markdownDescription": "Denies the disable command without any pre-configured scope." + }, + { + "description": "Denies the enable command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-enable", + "markdownDescription": "Denies the enable command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\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`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\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`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`", + "type": "string", + "const": "notification:default", + "markdownDescription": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`" + }, + { + "description": "Enables the batch command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-batch", + "markdownDescription": "Enables the batch command without any pre-configured scope." + }, + { + "description": "Enables the cancel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-cancel", + "markdownDescription": "Enables the cancel command without any pre-configured scope." + }, + { + "description": "Enables the check_permissions command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-check-permissions", + "markdownDescription": "Enables the check_permissions command without any pre-configured scope." + }, + { + "description": "Enables the create_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-create-channel", + "markdownDescription": "Enables the create_channel command without any pre-configured scope." + }, + { + "description": "Enables the delete_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-delete-channel", + "markdownDescription": "Enables the delete_channel command without any pre-configured scope." + }, + { + "description": "Enables the get_active command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-get-active", + "markdownDescription": "Enables the get_active command without any pre-configured scope." + }, + { + "description": "Enables the get_pending command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-get-pending", + "markdownDescription": "Enables the get_pending command without any pre-configured scope." + }, + { + "description": "Enables the is_permission_granted command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-is-permission-granted", + "markdownDescription": "Enables the is_permission_granted command without any pre-configured scope." + }, + { + "description": "Enables the list_channels command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-list-channels", + "markdownDescription": "Enables the list_channels command without any pre-configured scope." + }, + { + "description": "Enables the notify command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-notify", + "markdownDescription": "Enables the notify command without any pre-configured scope." + }, + { + "description": "Enables the permission_state command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-permission-state", + "markdownDescription": "Enables the permission_state command without any pre-configured scope." + }, + { + "description": "Enables the register_action_types command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-register-action-types", + "markdownDescription": "Enables the register_action_types command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_active command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-remove-active", + "markdownDescription": "Enables the remove_active command without any pre-configured scope." + }, + { + "description": "Enables the request_permission command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-request-permission", + "markdownDescription": "Enables the request_permission command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Denies the batch command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-batch", + "markdownDescription": "Denies the batch command without any pre-configured scope." + }, + { + "description": "Denies the cancel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-cancel", + "markdownDescription": "Denies the cancel command without any pre-configured scope." + }, + { + "description": "Denies the check_permissions command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-check-permissions", + "markdownDescription": "Denies the check_permissions command without any pre-configured scope." + }, + { + "description": "Denies the create_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-create-channel", + "markdownDescription": "Denies the create_channel command without any pre-configured scope." + }, + { + "description": "Denies the delete_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-delete-channel", + "markdownDescription": "Denies the delete_channel command without any pre-configured scope." + }, + { + "description": "Denies the get_active command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-get-active", + "markdownDescription": "Denies the get_active command without any pre-configured scope." + }, + { + "description": "Denies the get_pending command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-get-pending", + "markdownDescription": "Denies the get_pending command without any pre-configured scope." + }, + { + "description": "Denies the is_permission_granted command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-is-permission-granted", + "markdownDescription": "Denies the is_permission_granted command without any pre-configured scope." + }, + { + "description": "Denies the list_channels command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-list-channels", + "markdownDescription": "Denies the list_channels command without any pre-configured scope." + }, + { + "description": "Denies the notify command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-notify", + "markdownDescription": "Denies the notify command without any pre-configured scope." + }, + { + "description": "Denies the permission_state command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-permission-state", + "markdownDescription": "Denies the permission_state command without any pre-configured scope." + }, + { + "description": "Denies the register_action_types command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-register-action-types", + "markdownDescription": "Denies the register_action_types command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_active command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-remove-active", + "markdownDescription": "Denies the remove_active command without any pre-configured scope." + }, + { + "description": "Denies the request_permission command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-request-permission", + "markdownDescription": "Denies the request_permission command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-get-store`\n- `allow-set`\n- `allow-get`\n- `allow-has`\n- `allow-delete`\n- `allow-clear`\n- `allow-reset`\n- `allow-keys`\n- `allow-values`\n- `allow-entries`\n- `allow-length`\n- `allow-reload`\n- `allow-save`", + "type": "string", + "const": "store:default", + "markdownDescription": "This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-get-store`\n- `allow-set`\n- `allow-get`\n- `allow-has`\n- `allow-delete`\n- `allow-clear`\n- `allow-reset`\n- `allow-keys`\n- `allow-values`\n- `allow-entries`\n- `allow-length`\n- `allow-reload`\n- `allow-save`" + }, + { + "description": "Enables the clear command without any pre-configured scope.", + "type": "string", + "const": "store:allow-clear", + "markdownDescription": "Enables the clear command without any pre-configured scope." + }, + { + "description": "Enables the delete command without any pre-configured scope.", + "type": "string", + "const": "store:allow-delete", + "markdownDescription": "Enables the delete command without any pre-configured scope." + }, + { + "description": "Enables the entries command without any pre-configured scope.", + "type": "string", + "const": "store:allow-entries", + "markdownDescription": "Enables the entries command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "store:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the get_store command without any pre-configured scope.", + "type": "string", + "const": "store:allow-get-store", + "markdownDescription": "Enables the get_store command without any pre-configured scope." + }, + { + "description": "Enables the has command without any pre-configured scope.", + "type": "string", + "const": "store:allow-has", + "markdownDescription": "Enables the has command without any pre-configured scope." + }, + { + "description": "Enables the keys command without any pre-configured scope.", + "type": "string", + "const": "store:allow-keys", + "markdownDescription": "Enables the keys command without any pre-configured scope." + }, + { + "description": "Enables the length command without any pre-configured scope.", + "type": "string", + "const": "store:allow-length", + "markdownDescription": "Enables the length command without any pre-configured scope." + }, + { + "description": "Enables the load command without any pre-configured scope.", + "type": "string", + "const": "store:allow-load", + "markdownDescription": "Enables the load command without any pre-configured scope." + }, + { + "description": "Enables the reload command without any pre-configured scope.", + "type": "string", + "const": "store:allow-reload", + "markdownDescription": "Enables the reload command without any pre-configured scope." + }, + { + "description": "Enables the reset command without any pre-configured scope.", + "type": "string", + "const": "store:allow-reset", + "markdownDescription": "Enables the reset command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "store:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Enables the set command without any pre-configured scope.", + "type": "string", + "const": "store:allow-set", + "markdownDescription": "Enables the set command without any pre-configured scope." + }, + { + "description": "Enables the values command without any pre-configured scope.", + "type": "string", + "const": "store:allow-values", + "markdownDescription": "Enables the values command without any pre-configured scope." + }, + { + "description": "Denies the clear command without any pre-configured scope.", + "type": "string", + "const": "store:deny-clear", + "markdownDescription": "Denies the clear command without any pre-configured scope." + }, + { + "description": "Denies the delete command without any pre-configured scope.", + "type": "string", + "const": "store:deny-delete", + "markdownDescription": "Denies the delete command without any pre-configured scope." + }, + { + "description": "Denies the entries command without any pre-configured scope.", + "type": "string", + "const": "store:deny-entries", + "markdownDescription": "Denies the entries command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "store:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the get_store command without any pre-configured scope.", + "type": "string", + "const": "store:deny-get-store", + "markdownDescription": "Denies the get_store command without any pre-configured scope." + }, + { + "description": "Denies the has command without any pre-configured scope.", + "type": "string", + "const": "store:deny-has", + "markdownDescription": "Denies the has command without any pre-configured scope." + }, + { + "description": "Denies the keys command without any pre-configured scope.", + "type": "string", + "const": "store:deny-keys", + "markdownDescription": "Denies the keys command without any pre-configured scope." + }, + { + "description": "Denies the length command without any pre-configured scope.", + "type": "string", + "const": "store:deny-length", + "markdownDescription": "Denies the length command without any pre-configured scope." + }, + { + "description": "Denies the load command without any pre-configured scope.", + "type": "string", + "const": "store:deny-load", + "markdownDescription": "Denies the load command without any pre-configured scope." + }, + { + "description": "Denies the reload command without any pre-configured scope.", + "type": "string", + "const": "store:deny-reload", + "markdownDescription": "Denies the reload command without any pre-configured scope." + }, + { + "description": "Denies the reset command without any pre-configured scope.", + "type": "string", + "const": "store:deny-reset", + "markdownDescription": "Denies the reset command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "store:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." + }, + { + "description": "Denies the set command without any pre-configured scope.", + "type": "string", + "const": "store:deny-set", + "markdownDescription": "Denies the set command without any pre-configured scope." + }, + { + "description": "Denies the values command without any pre-configured scope.", + "type": "string", + "const": "store:deny-values", + "markdownDescription": "Denies the values command without any pre-configured scope." + } + ] + }, + "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" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/desktop/src-tauri/gen/schemas/linux-schema.json b/desktop/src-tauri/gen/schemas/linux-schema.json new file mode 100644 index 00000000..fb8b111d --- /dev/null +++ b/desktop/src-tauri/gen/schemas/linux-schema.json @@ -0,0 +1,2658 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "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" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`", + "type": "string", + "const": "autostart:default", + "markdownDescription": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`" + }, + { + "description": "Enables the disable command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-disable", + "markdownDescription": "Enables the disable command without any pre-configured scope." + }, + { + "description": "Enables the enable command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-enable", + "markdownDescription": "Enables the enable command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "autostart:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the disable command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-disable", + "markdownDescription": "Denies the disable command without any pre-configured scope." + }, + { + "description": "Denies the enable command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-enable", + "markdownDescription": "Denies the enable command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "autostart:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\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`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\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`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`", + "type": "string", + "const": "notification:default", + "markdownDescription": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`" + }, + { + "description": "Enables the batch command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-batch", + "markdownDescription": "Enables the batch command without any pre-configured scope." + }, + { + "description": "Enables the cancel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-cancel", + "markdownDescription": "Enables the cancel command without any pre-configured scope." + }, + { + "description": "Enables the check_permissions command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-check-permissions", + "markdownDescription": "Enables the check_permissions command without any pre-configured scope." + }, + { + "description": "Enables the create_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-create-channel", + "markdownDescription": "Enables the create_channel command without any pre-configured scope." + }, + { + "description": "Enables the delete_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-delete-channel", + "markdownDescription": "Enables the delete_channel command without any pre-configured scope." + }, + { + "description": "Enables the get_active command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-get-active", + "markdownDescription": "Enables the get_active command without any pre-configured scope." + }, + { + "description": "Enables the get_pending command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-get-pending", + "markdownDescription": "Enables the get_pending command without any pre-configured scope." + }, + { + "description": "Enables the is_permission_granted command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-is-permission-granted", + "markdownDescription": "Enables the is_permission_granted command without any pre-configured scope." + }, + { + "description": "Enables the list_channels command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-list-channels", + "markdownDescription": "Enables the list_channels command without any pre-configured scope." + }, + { + "description": "Enables the notify command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-notify", + "markdownDescription": "Enables the notify command without any pre-configured scope." + }, + { + "description": "Enables the permission_state command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-permission-state", + "markdownDescription": "Enables the permission_state command without any pre-configured scope." + }, + { + "description": "Enables the register_action_types command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-register-action-types", + "markdownDescription": "Enables the register_action_types command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_active command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-remove-active", + "markdownDescription": "Enables the remove_active command without any pre-configured scope." + }, + { + "description": "Enables the request_permission command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-request-permission", + "markdownDescription": "Enables the request_permission command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "notification:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Denies the batch command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-batch", + "markdownDescription": "Denies the batch command without any pre-configured scope." + }, + { + "description": "Denies the cancel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-cancel", + "markdownDescription": "Denies the cancel command without any pre-configured scope." + }, + { + "description": "Denies the check_permissions command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-check-permissions", + "markdownDescription": "Denies the check_permissions command without any pre-configured scope." + }, + { + "description": "Denies the create_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-create-channel", + "markdownDescription": "Denies the create_channel command without any pre-configured scope." + }, + { + "description": "Denies the delete_channel command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-delete-channel", + "markdownDescription": "Denies the delete_channel command without any pre-configured scope." + }, + { + "description": "Denies the get_active command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-get-active", + "markdownDescription": "Denies the get_active command without any pre-configured scope." + }, + { + "description": "Denies the get_pending command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-get-pending", + "markdownDescription": "Denies the get_pending command without any pre-configured scope." + }, + { + "description": "Denies the is_permission_granted command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-is-permission-granted", + "markdownDescription": "Denies the is_permission_granted command without any pre-configured scope." + }, + { + "description": "Denies the list_channels command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-list-channels", + "markdownDescription": "Denies the list_channels command without any pre-configured scope." + }, + { + "description": "Denies the notify command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-notify", + "markdownDescription": "Denies the notify command without any pre-configured scope." + }, + { + "description": "Denies the permission_state command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-permission-state", + "markdownDescription": "Denies the permission_state command without any pre-configured scope." + }, + { + "description": "Denies the register_action_types command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-register-action-types", + "markdownDescription": "Denies the register_action_types command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_active command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-remove-active", + "markdownDescription": "Denies the remove_active command without any pre-configured scope." + }, + { + "description": "Denies the request_permission command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-request-permission", + "markdownDescription": "Denies the request_permission command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "notification:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-get-store`\n- `allow-set`\n- `allow-get`\n- `allow-has`\n- `allow-delete`\n- `allow-clear`\n- `allow-reset`\n- `allow-keys`\n- `allow-values`\n- `allow-entries`\n- `allow-length`\n- `allow-reload`\n- `allow-save`", + "type": "string", + "const": "store:default", + "markdownDescription": "This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-get-store`\n- `allow-set`\n- `allow-get`\n- `allow-has`\n- `allow-delete`\n- `allow-clear`\n- `allow-reset`\n- `allow-keys`\n- `allow-values`\n- `allow-entries`\n- `allow-length`\n- `allow-reload`\n- `allow-save`" + }, + { + "description": "Enables the clear command without any pre-configured scope.", + "type": "string", + "const": "store:allow-clear", + "markdownDescription": "Enables the clear command without any pre-configured scope." + }, + { + "description": "Enables the delete command without any pre-configured scope.", + "type": "string", + "const": "store:allow-delete", + "markdownDescription": "Enables the delete command without any pre-configured scope." + }, + { + "description": "Enables the entries command without any pre-configured scope.", + "type": "string", + "const": "store:allow-entries", + "markdownDescription": "Enables the entries command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "store:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the get_store command without any pre-configured scope.", + "type": "string", + "const": "store:allow-get-store", + "markdownDescription": "Enables the get_store command without any pre-configured scope." + }, + { + "description": "Enables the has command without any pre-configured scope.", + "type": "string", + "const": "store:allow-has", + "markdownDescription": "Enables the has command without any pre-configured scope." + }, + { + "description": "Enables the keys command without any pre-configured scope.", + "type": "string", + "const": "store:allow-keys", + "markdownDescription": "Enables the keys command without any pre-configured scope." + }, + { + "description": "Enables the length command without any pre-configured scope.", + "type": "string", + "const": "store:allow-length", + "markdownDescription": "Enables the length command without any pre-configured scope." + }, + { + "description": "Enables the load command without any pre-configured scope.", + "type": "string", + "const": "store:allow-load", + "markdownDescription": "Enables the load command without any pre-configured scope." + }, + { + "description": "Enables the reload command without any pre-configured scope.", + "type": "string", + "const": "store:allow-reload", + "markdownDescription": "Enables the reload command without any pre-configured scope." + }, + { + "description": "Enables the reset command without any pre-configured scope.", + "type": "string", + "const": "store:allow-reset", + "markdownDescription": "Enables the reset command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "store:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Enables the set command without any pre-configured scope.", + "type": "string", + "const": "store:allow-set", + "markdownDescription": "Enables the set command without any pre-configured scope." + }, + { + "description": "Enables the values command without any pre-configured scope.", + "type": "string", + "const": "store:allow-values", + "markdownDescription": "Enables the values command without any pre-configured scope." + }, + { + "description": "Denies the clear command without any pre-configured scope.", + "type": "string", + "const": "store:deny-clear", + "markdownDescription": "Denies the clear command without any pre-configured scope." + }, + { + "description": "Denies the delete command without any pre-configured scope.", + "type": "string", + "const": "store:deny-delete", + "markdownDescription": "Denies the delete command without any pre-configured scope." + }, + { + "description": "Denies the entries command without any pre-configured scope.", + "type": "string", + "const": "store:deny-entries", + "markdownDescription": "Denies the entries command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "store:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the get_store command without any pre-configured scope.", + "type": "string", + "const": "store:deny-get-store", + "markdownDescription": "Denies the get_store command without any pre-configured scope." + }, + { + "description": "Denies the has command without any pre-configured scope.", + "type": "string", + "const": "store:deny-has", + "markdownDescription": "Denies the has command without any pre-configured scope." + }, + { + "description": "Denies the keys command without any pre-configured scope.", + "type": "string", + "const": "store:deny-keys", + "markdownDescription": "Denies the keys command without any pre-configured scope." + }, + { + "description": "Denies the length command without any pre-configured scope.", + "type": "string", + "const": "store:deny-length", + "markdownDescription": "Denies the length command without any pre-configured scope." + }, + { + "description": "Denies the load command without any pre-configured scope.", + "type": "string", + "const": "store:deny-load", + "markdownDescription": "Denies the load command without any pre-configured scope." + }, + { + "description": "Denies the reload command without any pre-configured scope.", + "type": "string", + "const": "store:deny-reload", + "markdownDescription": "Denies the reload command without any pre-configured scope." + }, + { + "description": "Denies the reset command without any pre-configured scope.", + "type": "string", + "const": "store:deny-reset", + "markdownDescription": "Denies the reset command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "store:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." + }, + { + "description": "Denies the set command without any pre-configured scope.", + "type": "string", + "const": "store:deny-set", + "markdownDescription": "Denies the set command without any pre-configured scope." + }, + { + "description": "Denies the values command without any pre-configured scope.", + "type": "string", + "const": "store:deny-values", + "markdownDescription": "Denies the values command without any pre-configured scope." + } + ] + }, + "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" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/desktop/src-tauri/icons/128x128.png b/desktop/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..77f90111f7afeeb215ab56077faea12f15d4404a GIT binary patch literal 3115 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 FV1jeUwHyEd literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/128x128@2x.png b/desktop/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2325cdb5e99f7f81631077de98e8bc31a7cde52f GIT binary patch literal 7953 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/icon.png b/desktop/src-tauri/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..283314e8fff7018b4d734a81120c15437f9417f5 GIT binary patch literal 7966 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/src/credentials.rs b/desktop/src-tauri/src/credentials.rs new file mode 100644 index 00000000..0d8eafba --- /dev/null +++ b/desktop/src-tauri/src/credentials.rs @@ -0,0 +1,70 @@ +use crate::notifications::Credentials; +use tauri::AppHandle; +use tauri_plugin_store::StoreExt; + +const STORE_FILE: &str = "credentials.json"; +const KEY_SERVER_URL: &str = "server_url"; +const KEY_AUTH_TOKEN: &str = "auth_token"; +const KEY_USER_ID: &str = "user_id"; + +/// Save credentials to the encrypted store +pub fn save(app: &AppHandle, credentials: &Credentials) -> Result<(), String> { + let store = app + .store(STORE_FILE) + .map_err(|e| format!("failed to open store: {}", e))?; + + store.set( + KEY_SERVER_URL, + serde_json::Value::String(credentials.server_url.clone()), + ); + store.set( + KEY_AUTH_TOKEN, + serde_json::Value::String(credentials.auth_token.clone()), + ); + store.set( + KEY_USER_ID, + serde_json::Value::String(credentials.user_id.clone()), + ); + + store + .save() + .map_err(|e| format!("failed to save store: {}", e))?; + + Ok(()) +} + +/// Load credentials from the encrypted store +pub fn load(app: &AppHandle) -> Option { + let store = app.store(STORE_FILE).ok()?; + + let server_url = store.get(KEY_SERVER_URL)?.as_str()?.to_string(); + let auth_token = store.get(KEY_AUTH_TOKEN)?.as_str()?.to_string(); + let user_id = store.get(KEY_USER_ID)?.as_str()?.to_string(); + + if server_url.is_empty() || auth_token.is_empty() || user_id.is_empty() { + return None; + } + + Some(Credentials { + server_url, + auth_token, + user_id, + }) +} + +/// Clear stored credentials +pub fn clear(app: &AppHandle) -> Result<(), String> { + let store = app + .store(STORE_FILE) + .map_err(|e| format!("failed to open store: {}", e))?; + + store.delete(KEY_SERVER_URL); + store.delete(KEY_AUTH_TOKEN); + store.delete(KEY_USER_ID); + + store + .save() + .map_err(|e| format!("failed to save store: {}", e))?; + + Ok(()) +} diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs new file mode 100644 index 00000000..bd1bda9c --- /dev/null +++ b/desktop/src-tauri/src/lib.rs @@ -0,0 +1,92 @@ +mod credentials; +mod notifications; +mod tray; + +use std::sync::Arc; + +use notifications::{Credentials, NotificationService}; +use tauri::Manager; +use tokio::sync::Mutex; + +type ServiceState = Arc>; + +#[tauri::command] +async fn start_notification_service( + app: tauri::AppHandle, + state: tauri::State<'_, ServiceState>, + server_url: String, + auth_token: String, + user_id: String, +) -> Result<(), String> { + let creds = Credentials { + server_url, + auth_token, + user_id, + }; + + // Persist credentials for auto-reconnect on next launch + credentials::save(&app, &creds)?; + + notifications::start(&app, &state, creds).await; + Ok(()) +} + +#[tauri::command] +async fn stop_notification_service( + app: tauri::AppHandle, + state: tauri::State<'_, ServiceState>, +) -> Result<(), String> { + notifications::stop(&app, &state).await; + credentials::clear(&app)?; + Ok(()) +} + +#[tauri::command] +async fn get_service_status(state: tauri::State<'_, ServiceState>) -> Result { + let status = notifications::status(&state).await; + Ok(serde_json::to_string(&status).unwrap_or_else(|_| "\"disconnected\"".to_string())) +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_notification::init()) + .plugin(tauri_plugin_autostart::init( + tauri_plugin_autostart::MacosLauncher::LaunchAgent, + Some(vec!["--minimized"]), + )) + .plugin(tauri_plugin_store::Builder::default().build()) + .manage(NotificationService::new()) + .invoke_handler(tauri::generate_handler![ + start_notification_service, + stop_notification_service, + get_service_status, + ]) + .setup(|app| { + tray::setup(app.handle())?; + + // Hide window on close (minimize to tray) instead of quitting + let window = app.get_webview_window("main").unwrap(); + let window_clone = window.clone(); + window.on_window_event(move |event| { + if let tauri::WindowEvent::CloseRequested { api, .. } = event { + api.prevent_close(); + let _ = window_clone.hide(); + } + }); + + // Auto-connect if credentials are saved from a previous session + let app_handle = app.handle().clone(); + tauri::async_runtime::spawn(async move { + if let Some(creds) = credentials::load(&app_handle) { + log::info!("Found saved credentials, auto-connecting..."); + let state: tauri::State<'_, ServiceState> = app_handle.state(); + notifications::start(&app_handle, &state, creds).await; + } + }); + + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs new file mode 100644 index 00000000..1077207a --- /dev/null +++ b/desktop/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + quack_desktop_lib::run() +} diff --git a/desktop/src-tauri/src/notifications.rs b/desktop/src-tauri/src/notifications.rs new file mode 100644 index 00000000..f795b27d --- /dev/null +++ b/desktop/src-tauri/src/notifications.rs @@ -0,0 +1,306 @@ +use std::sync::Arc; +use std::time::Duration; + +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use tauri::{AppHandle, Emitter, Manager}; +use tauri_plugin_notification::NotificationExt; +use tokio::sync::Mutex; +use tokio::task::JoinHandle; + +/// Connection state reported to the frontend and tray +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ConnectionStatus { + Disconnected, + Connecting, + Connected, + Reconnecting, +} + +/// Notification event from the server SSE stream +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(dead_code)] +struct NotificationEvent { + #[serde(rename = "type")] + event_type: Option, + channel_id: Option, + parent_id: Option, + title: Option, + body: Option, + sender_id: Option, + sender_name: Option, +} + +/// Credentials needed for the SSE connection +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Credentials { + pub server_url: String, + pub auth_token: String, + pub user_id: String, +} + +/// Shared state for the notification service +pub struct NotificationService { + task: Option>, + status: ConnectionStatus, + credentials: Option, +} + +impl NotificationService { + pub fn new() -> Arc> { + Arc::new(Mutex::new(Self { + task: None, + status: ConnectionStatus::Disconnected, + credentials: None, + })) + } +} + +/// Start the SSE notification service +pub async fn start( + app: &AppHandle, + service: &Arc>, + credentials: Credentials, +) { + let mut svc = service.lock().await; + + // Stop existing task if running + if let Some(task) = svc.task.take() { + task.abort(); + } + + svc.credentials = Some(credentials.clone()); + svc.status = ConnectionStatus::Connecting; + drop(svc); + + update_tray_tooltip(app, &ConnectionStatus::Connecting); + let _ = app.emit("notification-service-status", "connecting"); + + let app_handle = app.clone(); + let service_clone = Arc::clone(service); + + let task = tokio::spawn(async move { + sse_loop(&app_handle, &service_clone, &credentials).await; + }); + + let mut svc = service.lock().await; + svc.task = Some(task); +} + +/// Stop the SSE notification service +pub async fn stop(app: &AppHandle, service: &Arc>) { + let mut svc = service.lock().await; + + if let Some(task) = svc.task.take() { + task.abort(); + } + + svc.status = ConnectionStatus::Disconnected; + svc.credentials = None; + + update_tray_tooltip(app, &ConnectionStatus::Disconnected); + let _ = app.emit("notification-service-status", "disconnected"); +} + +/// Get current connection status +pub async fn status(service: &Arc>) -> ConnectionStatus { + let svc = service.lock().await; + svc.status.clone() +} + +/// Main SSE loop with exponential backoff reconnection +async fn sse_loop( + app: &AppHandle, + service: &Arc>, + credentials: &Credentials, +) { + let client = Client::builder() + .connect_timeout(Duration::from_secs(30)) + .build() + .expect("failed to create HTTP client"); + + let mut backoff = Duration::from_secs(1); + let max_backoff = Duration::from_secs(60); + + loop { + let url = format!( + "{}/api/notifications", + credentials.server_url.trim_end_matches('/') + ); + + log::info!("SSE connecting to {}", url); + set_status(app, service, ConnectionStatus::Connecting).await; + + match connect_sse(&client, &url, &credentials.auth_token, &credentials.user_id, app).await + { + Ok(()) => { + // Clean disconnect — server closed the stream + log::info!("SSE stream ended cleanly"); + backoff = Duration::from_secs(1); + } + Err(e) => { + log::error!("SSE connection error: {}", e); + } + } + + set_status(app, service, ConnectionStatus::Reconnecting).await; + + log::info!("Reconnecting in {:?}", backoff); + tokio::time::sleep(backoff).await; + + // Exponential backoff: 1s → 2s → 4s → ... → 60s + backoff = (backoff * 2).min(max_backoff); + } +} + +/// Connect to the SSE endpoint and process events +async fn connect_sse( + client: &Client, + url: &str, + token: &str, + user_id: &str, + app: &AppHandle, +) -> Result<(), String> { + let response = client + .get(url) + .header("Authorization", format!("Bearer {}", token)) + .header("Accept", "text/event-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .map_err(|e| format!("request failed: {}", e))?; + + if !response.status().is_success() { + return Err(format!("HTTP {}", response.status())); + } + + let mut buffer = String::new(); + let mut stream = response.bytes_stream(); + + use futures_util::StreamExt; + + let mut connected = false; + + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("stream read error: {}", e))?; + let text = String::from_utf8_lossy(&chunk); + buffer.push_str(&text); + + // Process complete SSE messages (terminated by double newline) + while let Some(pos) = buffer.find("\n\n") { + let message = buffer[..pos].to_string(); + buffer = buffer[pos + 2..].to_string(); + + if let Some(data) = extract_sse_data(&message) { + if !connected { + // First message is the connection confirmation + connected = true; + let _ = app.emit("notification-service-status", "connected"); + // Reset tray to connected + update_tray_tooltip(app, &ConnectionStatus::Connected); + log::info!("SSE connected"); + continue; + } + + handle_event(data, user_id, app); + } + } + } + + Ok(()) +} + +/// Extract the `data:` field from an SSE message +fn extract_sse_data(message: &str) -> Option<&str> { + for line in message.lines() { + if let Some(data) = line.strip_prefix("data:") { + return Some(data.trim()); + } + } + None +} + +/// Handle a parsed SSE event +fn handle_event(data: &str, user_id: &str, app: &AppHandle) { + let event: NotificationEvent = match serde_json::from_str(data) { + Ok(e) => e, + Err(e) => { + log::warn!("Failed to parse SSE event: {} — data: {}", e, data); + return; + } + }; + + // Ignore pings + if event.event_type.as_deref() == Some("ping") { + return; + } + + // Ignore non-notification events + if event.event_type.as_deref() != Some("notification") { + return; + } + + // Skip own messages (server should already filter, but double-check) + if event.sender_id.as_deref() == Some(user_id) { + return; + } + + let title = event.title.unwrap_or_else(|| "New message".to_string()); + let body = event.body.unwrap_or_default(); + + // Check if main window is visible and focused — suppress notification if so + if let Some(window) = app.get_webview_window("main") { + if window.is_visible().unwrap_or(false) && window.is_focused().unwrap_or(false) { + // Window is focused, emit event for the web app but skip OS notification + let _ = app.emit("notification-message", data); + return; + } + } + + // Fire OS notification + let _ = app + .notification() + .builder() + .title(&title) + .body(&body) + .show(); + + // Also emit to the web app for in-app handling + let _ = app.emit("notification-message", data); +} + +/// Update the tray tooltip with connection status +fn update_tray_tooltip(app: &AppHandle, status: &ConnectionStatus) { + if let Some(tray) = app.tray_by_id("main") { + let tooltip = match status { + ConnectionStatus::Connected => "Quack — Connected", + ConnectionStatus::Connecting => "Quack — Connecting...", + ConnectionStatus::Reconnecting => "Quack — Reconnecting...", + ConnectionStatus::Disconnected => "Quack — Disconnected", + }; + let _ = tray.set_tooltip(Some(tooltip)); + } +} + +/// Update shared status and emit event +async fn set_status( + app: &AppHandle, + service: &Arc>, + new_status: ConnectionStatus, +) { + let mut svc = service.lock().await; + svc.status = new_status.clone(); + drop(svc); + + let status_str = match new_status { + ConnectionStatus::Connected => "connected", + ConnectionStatus::Connecting => "connecting", + ConnectionStatus::Reconnecting => "reconnecting", + ConnectionStatus::Disconnected => "disconnected", + }; + + update_tray_tooltip(app, &new_status); + let _ = app.emit("notification-service-status", status_str); +} diff --git a/desktop/src-tauri/src/tray.rs b/desktop/src-tauri/src/tray.rs new file mode 100644 index 00000000..a1a2c640 --- /dev/null +++ b/desktop/src-tauri/src/tray.rs @@ -0,0 +1,41 @@ +use tauri::{ + AppHandle, Manager, + menu::{Menu, MenuItem}, + tray::TrayIconEvent, +}; + +pub fn setup(app: &AppHandle) -> Result<(), Box> { + let show = MenuItem::with_id(app, "show", "Show Quack", true, None::<&str>)?; + let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; + + let menu = Menu::with_items(app, &[&show, &quit])?; + + let tray = app.tray_by_id("main").expect("tray not found"); + tray.set_menu(Some(menu))?; + tray.set_tooltip(Some("Quack — Disconnected"))?; + + tray.on_menu_event(move |app, event| match event.id().as_ref() { + "show" => { + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + "quit" => { + app.exit(0); + } + _ => {} + }); + + tray.on_tray_icon_event(|tray, event| { + if let TrayIconEvent::Click { .. } = event { + let app = tray.app_handle(); + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + }); + + Ok(()) +} diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json new file mode 100644 index 00000000..59a50e7b --- /dev/null +++ b/desktop/src-tauri/tauri.conf.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://raw.githubusercontent.com/niccolocase/niccolocase/main/packages/tauri/src/api/config.schema.json", + "productName": "Quack", + "version": "0.1.0", + "identifier": "io.codecat.quack", + "build": { + "frontendDist": "../src" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "Quack", + "width": 1200, + "height": 800, + "minWidth": 400, + "minHeight": 600, + "center": true, + "url": "index.html" + } + ], + "trayIcon": { + "iconPath": "icons/icon.png", + "iconAsTemplate": true, + "tooltip": "Quack" + }, + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.ico", + "icons/icon.png" + ], + "linux": { + "deb": { + "depends": ["libwebkit2gtk-4.1-0", "libappindicator3-1"] + }, + "appimage": { + "bundleMediaFramework": false + } + } + } +} diff --git a/desktop/src/index.html b/desktop/src/index.html new file mode 100644 index 00000000..bfc6a565 --- /dev/null +++ b/desktop/src/index.html @@ -0,0 +1,115 @@ + + + + + Quack + + + +

Quack

+

Enter your Quack server URL to connect

+ +
+ + + + + diff --git a/docs/adr/015-tauri-desktop-app.md b/docs/adr/015-tauri-desktop-app.md new file mode 100644 index 00000000..7d957d97 --- /dev/null +++ b/docs/adr/015-tauri-desktop-app.md @@ -0,0 +1,47 @@ +# ADR 015: Tauri v2 for Desktop Application + +## Status + +Accepted + +## Context + +Quack is a self-hosted chat application that prioritizes privacy, instant delivery, and independence from third-party services. The mobile app (Capacitor + native Android foreground service) already implements a custom SSE-based push notification system (ADR 013) that delivers notifications instantly without relying on FCM or Google Play Services. + +Desktop users currently rely on the PWA installed from the browser. While functional for the main UI, PWA push notifications are unreliable — browsers batch and throttle Web Push delivery, often resulting in delays of seconds to minutes. This defeats the purpose of a real-time chat application. + +Desktop needs the same notification reliability as mobile: a persistent SSE connection that delivers notifications instantly, independent of browser state. + +Options considered: + +1. **Capacitor + Electron** — Capacitor supports Electron via community plugins, but Electron bundles Chromium (~150MB), the Capacitor-Electron ecosystem is small and community-maintained, and it goes against the lightweight ethos of the project. + +2. **Tauri v2** — Rust-based, uses the OS native webview (~8-15MB binary), has built-in system tray support, native notifications, and autostart plugins. The Rust backend can maintain a persistent SSE connection independently of the webview. + +3. **Improve PWA Push** — Wire up VAPID keys and complete Web Push. Zero maintenance but fundamentally limited by browser throttling, requires browser to be running, and depends on browser vendors' push infrastructure. + +## Decision + +Use **Tauri v2** to build a desktop application that mirrors the mobile app's architecture: a native shell loading the web UI from the server, with a background service maintaining a persistent SSE connection for instant notifications. + +Key architectural choices: + +- **Server-loaded webview** — the Tauri window loads content from the Quack server URL (same as Capacitor mobile), no frontend bundling needed. +- **Rust SSE service** — a tokio async task maintains a persistent connection to `/api/notifications` (renamed from `/api/mobile/notifications` to reflect multi-platform use). +- **System tray** — the app minimizes to the system tray instead of closing, keeping the SSE connection alive. +- **Separate package** — lives in `desktop/` alongside `mobile/`, following the same pattern of a native shell wrapping the web app. +- **Shared notification endpoint** — reuses the existing server-side SSE notification infrastructure with no backend changes needed. + +## Consequences + +- **Positive:** Instant notifications — same SSE delivery as mobile, no browser throttling. +- **Positive:** Lightweight — ~8-15MB binary vs ~150MB for Electron. +- **Positive:** Privacy-preserving — no notification metadata leaves the user's server, consistent with ADR 013. +- **Positive:** Self-contained — no dependency on browser push infrastructure or external services. +- **Positive:** Cross-platform — single codebase targets Windows, macOS, and Linux. +- **Positive:** System tray — app stays connected in background without occupying taskbar space. +- **Positive:** Reuses existing infrastructure — same `/api/notifications` endpoint, same event format, same auth mechanism. +- **Negative:** Rust requirement — contributors need Rust toolchain for desktop app development. +- **Negative:** Platform-specific quirks — system tray behavior, autostart, and notification APIs vary across Windows/macOS/Linux. +- **Negative:** Additional build targets — CI needs to build for 3 desktop platforms (vs 1 for mobile). +- **Negative:** Webview differences — OS webviews (WebKit on macOS/Linux, WebView2 on Windows) may have rendering differences compared to Chromium. diff --git a/docs/adr/README.md b/docs/adr/README.md index 7bf54ba6..2f1c131f 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -20,6 +20,7 @@ This directory contains Architecture Decision Records (ADRs) for Quack Chat. | [012](012-pwa-first.md) | PWA-first with Capacitor native shell for Android | Accepted | | [013](013-custom-push-notifications.md) | Custom push notifications via SSE (no FCM/Google dependency) | Accepted | | [014](014-repository-pattern-over-orm.md) | Repository pattern over ORM for database access | Accepted | +| [015](015-tauri-desktop-app.md) | Tauri v2 for desktop app with SSE notifications | Accepted | ## Format diff --git a/docs/desktop-app-plan.md b/docs/desktop-app-plan.md new file mode 100644 index 00000000..cd348e01 --- /dev/null +++ b/docs/desktop-app-plan.md @@ -0,0 +1,159 @@ +# Desktop App — Execution Plan + +Step-by-step plan for implementing the Tauri v2 desktop app with SSE-based instant notifications. + +## Phase 1: Project Scaffold + +**Goal**: Tauri app opens a window loading the Quack server URL. + +- [ ] Initialize `desktop/` directory with `npm create tauri-app` +- [ ] Configure `tauri.conf.json`: + - App identifier: `io.codecat.quack` + - Window: title "Quack", default size 1200x800, min size 400x600 + - Server URL loading (no bundled frontend) +- [ ] Add npm scripts: `tauri dev`, `tauri build` +- [ ] Verify: app opens, loads web UI from server, login works + +**Deliverable**: Minimal Tauri shell that displays the Quack web app. + +## Phase 2: System Tray + +**Goal**: App minimizes to tray instead of quitting, with status menu. + +- [ ] Add `tauri-plugin-tray` (built into Tauri v2 with `tray-icon` feature) +- [ ] Create tray icon (reuse existing Quack icon assets) +- [ ] Implement tray menu: Show/Hide, separator, Quit +- [ ] Window close → hide to tray (not quit) +- [ ] Tray icon click → show/focus window +- [ ] Verify: closing window keeps app in tray, tray menu works + +**Deliverable**: App persists in system tray when window is closed. + +## Phase 3: SSE Notification Service + +**Goal**: Rust backend maintains persistent SSE connection, fires OS notifications. + +- [ ] Add `reqwest` with streaming support +- [ ] Implement SSE client in `notifications.rs`: + - Connect to `/api/notifications` with bearer token + - Parse SSE events (data-only, no event types) + - Handle heartbeat pings (keep-alive) + - Exponential backoff reconnection (1s → 60s) +- [ ] Add `tauri-plugin-notification` for native OS notifications +- [ ] Implement IPC commands: + - `start_notification_service(server_url, auth_token, user_id)` + - `stop_notification_service()` + - `get_service_status()` → connected/reconnecting/disconnected +- [ ] Fire OS notification on message event (skip self-messages) +- [ ] Update tray icon/tooltip with connection status +- [ ] Verify: receive instant notification when message sent from another user + +**Deliverable**: Background SSE connection with native notifications. + +## Phase 4: Credential Storage & Auto-connect + +**Goal**: Persist credentials securely, reconnect on app launch. + +- [ ] Add `tauri-plugin-store` for encrypted credential storage +- [ ] Store `server_url`, `auth_token`, `user_id` on successful service start +- [ ] On app launch, check for stored credentials → auto-start SSE service +- [ ] Clear credentials on explicit logout / `stop_notification_service()` +- [ ] Verify: restart app → notifications resume without re-login + +**Deliverable**: Seamless reconnection across app restarts. + +## Phase 5: Web App Integration + +**Goal**: Web app detects Tauri and bridges notification service. + +- [ ] Create `desktop/src/bridge.ts` with Tauri IPC wrappers +- [ ] Add platform detection in `app/src/js/core/notifications.ts`: + - If Tauri → use IPC commands (like Capacitor plugin on mobile) + - If browser → use existing PWA/SW path +- [ ] Wire up login → `start_notification_service` +- [ ] Wire up logout → `stop_notification_service` +- [ ] Notification click → IPC message to navigate to channel/thread +- [ ] Verify: full flow — login, receive notification, click to navigate + +**Deliverable**: Web app seamlessly controls the native notification service. + +## Phase 6: Autostart & Polish + +**Goal**: Optional launch on OS boot, notification sound, polish. + +- [ ] Add `tauri-plugin-autostart` with user toggle +- [ ] Add custom notification sound (`quack_notification.wav`) +- [ ] Add notification grouping (collapse multiple messages from same channel) +- [ ] Handle window focus → suppress notifications for active channel +- [ ] Test on all 3 platforms (Linux, macOS, Windows) +- [ ] Verify: autostart works, sound plays, no duplicate notifications + +**Deliverable**: Production-ready desktop app. + +## Phase 7: Backend Cleanup + +**Goal**: Rename endpoint, ensure multi-platform readiness. + +- [ ] Rename route mount: `/api/mobile/notifications` → `/api/notifications` +- [ ] Keep `/api/mobile/notifications` as alias for backwards compatibility with existing mobile builds +- [ ] Update mobile app to use new endpoint path (next mobile release) +- [ ] Update docs and tests + +**Deliverable**: Clean, platform-agnostic notification endpoint. + +## Phase 8: CI & Distribution + +**Goal**: Automated builds and releases. + +- [ ] Add GitHub Actions workflow for desktop builds: + - Matrix: ubuntu-latest, macos-latest, windows-latest + - Trigger: release tag or manual dispatch + - Output: `.deb`, `.AppImage`, `.dmg`, `.msi` +- [ ] Attach desktop binaries to GitHub Releases +- [ ] Optional: Tauri updater plugin for in-app auto-updates +- [ ] Add build instructions to `docs/desktop-app.md` + +**Deliverable**: Users can download desktop app from GitHub Releases. + +--- + +## Dependencies Between Phases + +``` +Phase 1 (Scaffold) + └── Phase 2 (System Tray) + └── Phase 3 (SSE Notifications) ◄── core feature + ├── Phase 4 (Credentials) + ├── Phase 5 (Web Integration) + │ └── Phase 6 (Polish) + │ └── Phase 8 (CI) + └── Phase 7 (Backend Cleanup) ◄── independent +``` + +Phases 1–3 are the MVP. Phases 4–6 bring it to production quality. Phases 7–8 are housekeeping. + +## Estimated Scope + +| Phase | New files | Complexity | +|---|---|---| +| 1. Scaffold | ~5 (config, cargo, main) | Low | +| 2. System Tray | ~1 (tray.rs) | Low | +| 3. SSE Notifications | ~2 (notifications.rs, credentials.rs) | Medium | +| 4. Credential Storage | Edit existing | Low | +| 5. Web Integration | ~1 (bridge.ts) + edit notifications.ts | Medium | +| 6. Polish | Edits across files | Low | +| 7. Backend Cleanup | Route rename + alias | Low | +| 8. CI | ~1 workflow file | Medium | + +## Tech Stack Summary + +| Layer | Technology | +|---|---| +| Shell | Tauri v2 | +| Async runtime | tokio | +| HTTP/SSE client | reqwest (streaming) | +| Notifications | tauri-plugin-notification | +| Storage | tauri-plugin-store | +| Autostart | tauri-plugin-autostart | +| System tray | Tauri built-in (tray-icon feature) | +| Build/package | tauri-cli (deb, AppImage, dmg, msi) | diff --git a/docs/desktop-app.md b/docs/desktop-app.md new file mode 100644 index 00000000..ec729a84 --- /dev/null +++ b/docs/desktop-app.md @@ -0,0 +1,204 @@ +# Desktop App + +Quack provides a native desktop app built with [Tauri v2](https://v2.tauri.app/) that wraps the web application with a persistent background notification service. The app connects directly to your Quack server via SSE for instant, private notifications — no browser required. + +## Architecture + +``` +desktop/ +├── package.json # npm scripts for dev/build +├── src-tauri/ +│ ├── Cargo.toml # Rust dependencies +│ ├── tauri.conf.json # Tauri config (window, tray, permissions) +│ ├── capabilities/ # Tauri v2 permission capabilities +│ └── src/ +│ ├── main.rs # App entry, window management, IPC commands +│ ├── tray.rs # System tray setup and menu +│ ├── notifications.rs # SSE client, native notification dispatch +│ └── credentials.rs # Secure credential storage +└── src/ # Thin bridge layer (optional) + └── bridge.ts # Tauri IPC bindings for the web app +``` + +### How It Works + +The desktop app follows the same architecture as the mobile app (see [ADR 013](adr/013-custom-push-notifications.md)): + +``` +┌─────────────────────────────────────────────────────┐ +│ Desktop App (Tauri) │ +│ │ +│ ┌──────────────┐ ┌──────────────────────────┐ │ +│ │ Webview │ │ Rust Backend │ │ +│ │ │ │ │ │ +│ │ Quack Web │◄──►│ IPC Commands │ │ +│ │ UI (from │ │ start/stop service │ │ +│ │ server) │ │ get status │ │ +│ │ │ │ │ │ +│ └──────────────┘ │ SSE Notification Task │ │ +│ │ tokio async task │ │ +│ │ reqwest SSE client │ │ +│ │ ─► OS Notification │ │ +│ │ │ │ +│ │ System Tray │ │ +│ │ connection status │ │ +│ │ show/quit menu │ │ +│ └──────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────┘ + │ │ + │ HTTPS (web UI) │ SSE (/api/notifications) + ▼ ▼ +┌─────────────────────────────────────────────────────┐ +│ Quack Server │ +└─────────────────────────────────────────────────────┘ +``` + +1. User launches the app → Tauri window loads the Quack server URL +2. User logs in through the web UI +3. Web app calls Tauri IPC → Rust starts an async SSE connection to `/api/notifications` +4. Server pushes message events → Rust fires native OS notification immediately +5. User closes window → app minimizes to system tray, SSE stays connected +6. Clicking a notification → app window opens/focuses at the relevant channel + +### Comparison with Mobile + +| Component | Mobile (Android) | Desktop (Tauri) | +|---|---|---| +| Shell | Capacitor | Tauri v2 | +| SSE client | OkHttp (Kotlin) | reqwest (Rust) | +| Notifications | Android NotificationManager | tauri-plugin-notification | +| Background | Foreground Service | System tray | +| Credential storage | EncryptedSharedPreferences | tauri-plugin-store | +| Auto-start | BootReceiver | tauri-plugin-autostart | +| Deep links | `quack://` intent | IPC → window navigation | + +## Rust Dependencies + +```toml +[dependencies] +tauri = { version = "2", features = ["tray-icon"] } +tauri-plugin-notification = "2" +tauri-plugin-autostart = "2" +tauri-plugin-store = "2" +reqwest = { version = "0.12", features = ["stream"] } +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +``` + +## IPC Commands + +The web app communicates with the Rust backend via Tauri's IPC: + +| Command | Parameters | Description | +|---|---|---| +| `start_notification_service` | `server_url`, `auth_token`, `user_id` | Start SSE connection | +| `stop_notification_service` | — | Stop SSE connection | +| `get_service_status` | — | Returns connection state | + +These mirror the Capacitor plugin interface (`QuackPlugin`) used by the mobile app, so the web app's notification initialization code can target both platforms with minimal branching. + +## SSE Notification Service + +The Rust notification service connects to the same endpoint as mobile: + +- **Endpoint**: `GET /api/notifications` (SSE stream, bearer auth) +- **Heartbeat**: Server sends `{"type":"ping"}` every 30s +- **Events**: `{"type":"notification", "channelId":"...", "title":"...", "body":"...", "senderId":"...", "senderName":"..."}` +- **Reconnect**: Exponential backoff (1s → 60s max) on connection failure +- **Self-message filtering**: Server already filters, client double-checks + +## System Tray + +The app runs in the system tray when the window is closed: + +- **Tray icon**: Quack icon with connection status indicator +- **Menu items**: + - Show/Hide window + - Connection status (connected/reconnecting/disconnected) + - Quit +- **Click behavior**: Single-click shows window, right-click opens menu + +## Prerequisites + +- [Rust](https://rustup.rs/) (stable toolchain) +- Node.js and npm +- Platform-specific requirements: + - **Linux**: `libwebkit2gtk-4.1-dev`, `libappindicator3-dev`, `librsvg2-dev`, `libssl-dev` + - **macOS**: Xcode Command Line Tools + - **Windows**: WebView2 (pre-installed on Windows 10/11), Visual Studio Build Tools +- A deployed Quack server + +## Quick Start + +### 1. Configure Server URL + +```bash +cd desktop +cp .env.example .env +# Edit .env with your QUACK_SERVER_URL +``` + +### 2. Install Dependencies + +```bash +cd desktop +npm install +``` + +### 3. Development + +```bash +npm run tauri dev +``` + +This opens the app pointing at your configured server URL with hot-reload for Rust changes. + +### 4. Build + +```bash +# Build for current platform +npm run tauri build +``` + +Produces platform-specific installers in `desktop/src-tauri/target/release/bundle/`: +- **Linux**: `.deb`, `.AppImage` +- **macOS**: `.dmg`, `.app` +- **Windows**: `.msi`, `.exe` + +## Notification Sound + +Place a custom notification sound at: +``` +desktop/src-tauri/resources/quack_notification.wav +``` + +## Configuration + +The app stores its configuration (server URL, credentials) securely using `tauri-plugin-store` with OS-level encryption: +- **Linux**: `$XDG_DATA_HOME/io.codecat.quack/` (libsecret) +- **macOS**: `~/Library/Application Support/io.codecat.quack/` (Keychain) +- **Windows**: `%APPDATA%/io.codecat.quack/` (DPAPI) + +## Troubleshooting + +### Notifications not showing +1. Check OS notification settings for Quack +2. Verify the system tray icon shows "Connected" +3. Check the dev console (right-click → Inspect) for errors + +### Connection issues +1. Verify server URL is correct and accessible +2. Check if the SSE endpoint responds: `curl -H "Authorization: Bearer TOKEN" https://your-server/api/notifications` +3. Check system tray tooltip for connection status + +### Linux-specific +1. Ensure `libappindicator3` is installed for system tray support +2. On Wayland, some tray implementations may behave differently +3. If notifications don't appear, check if a notification daemon is running (`dunst`, `mako`, etc.) + +### Build issues +1. Run `rustup update` to ensure latest Rust toolchain +2. On Linux, install all webkit/gtk dependencies (see Prerequisites) +3. Clear build cache: `cd desktop/src-tauri && cargo clean` From 3591fd3a1ade427b470ae8cc6162f1420466c1ec Mon Sep 17 00:00:00 2001 From: Mateusz Russak Date: Thu, 19 Feb 2026 17:51:18 +0100 Subject: [PATCH 3/6] fix(desktop): build --- BACKLOG.md | 23 +++- app/src/js/components/contexts/tooltip.tsx | 4 +- .../js/components/molecules/ActionButton.tsx | 4 +- .../js/components/molecules/NavChannels.tsx | 2 +- app/src/js/components/molecules/NavUsers.tsx | 10 +- .../js/components/molecules/UserMention.tsx | 2 +- app/src/js/components/organisms/Search.tsx | 2 +- app/src/js/components/pages/ErrorPage.tsx | 2 +- app/src/js/components/pages/Register.tsx | 5 +- app/src/js/core/client.ts | 4 +- app/src/js/core/models/files.ts | 4 +- app/src/js/core/models/input.ts | 1 + app/src/js/core/models/message.ts | 2 +- app/src/js/core/plugins.ts | 8 +- app/src/js/utils.ts | 2 +- deno/api/auth.ts | 9 +- deno/api/files.ts | 6 +- deno/api/messageTypes.ts | 4 +- deno/api/mod.ts | 51 +++++---- deno/config/types.ts | 2 +- deno/encryption/mod.ts | 8 +- deno/migrate/mod.ts | 2 +- deno/server/app.ts | 4 +- deno/server/core/bus.ts | 26 +++-- deno/server/core/command.ts | 35 +++---- deno/server/core/core.ts | 17 ++- deno/server/core/message/create.ts | 9 +- deno/server/core/query.ts | 7 +- deno/server/core/serializer.ts | 15 ++- deno/server/core/webhooks.ts | 6 +- deno/server/infra/repo/channelRepo.ts | 2 +- deno/server/infra/repo/serializer.ts | 38 ++++--- deno/server/infra/repo/userRepo.ts | 5 +- deno/server/inter/cli/mod.ts | 12 ++- deno/server/inter/http/mod.ts | 2 +- .../inter/http/routes/__tests__/chat.ts | 98 +++++++++++++----- .../inter/http/routes/__tests__/users.ts | 1 + .../routes/auth/__tests__/session.test.ts | 14 +-- .../routes/channel/__tests__/channels.test.ts | 6 +- .../routes/channel/__tests__/direct.test.ts | 2 +- .../inter/http/routes/channel/postChannel.ts | 2 +- .../inter/http/routes/channel/putDirect.ts | 2 +- .../commands/__tests__/commands.test.ts | 35 ++++--- .../routes/emojis/__tests__/emojis.test.ts | 2 +- .../__tests__/interaction.test.ts | 6 +- .../routes/messages/__tests__/format.test.ts | 6 +- .../messages/__tests__/messages.test.ts | 29 ++++-- .../messages/__tests__/notifications.test.ts | 8 +- .../routes/messages/__tests__/pinning.test.ts | 12 +-- .../routes/messages/__tests__/react.test.ts | 50 +++++---- .../routes/messages/__tests__/threads.test.ts | 10 +- .../inter/http/routes/messages/create.ts | 2 +- .../inter/http/routes/mobile/notifications.ts | 3 +- .../routes/profile/__tests__/profile.test.ts | 2 +- .../readReceipt/__tests__/readReceipt.test.ts | 22 ++-- .../users/__tests__/registration.test.ts | 10 +- .../http/routes/users/__tests__/users.test.ts | 12 +-- deno/server/inter/http/routes/users/create.ts | 2 +- deno/storage/src/core/mod.ts | 14 ++- deno/storage/src/core/streams.ts | 30 ++---- deno/tools/cache.ts | 6 +- desktop/src-tauri/icons/icon.ico | Bin 59329 -> 24621 bytes 62 files changed, 431 insertions(+), 290 deletions(-) diff --git a/BACKLOG.md b/BACKLOG.md index 71d9787a..8c009dcf 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -115,10 +115,13 @@ Create standard story template with: ## 2. Code Cleanup ### 2.1 Type Safety (HIGH PRIORITY) -- [ ] Fix pre-existing TypeScript errors (17 errors in base) -- [ ] Remove `any` types - 20 instances in app/src -- [ ] Fix `style: any` unused prop in `ActionButton.tsx:10` -- [ ] Add proper typing to API module (`deno/api/mod.ts` - `payload: any`, `document: any`) +- [ ] Fix pre-existing TypeScript errors (16 errors in base) +- [x] Remove `any` types from backend core (serializers, bus, command/query, repos, HTTP/CLI) — PR #272 +- [x] Remove `any` types from storage, encryption, config, migrate, tools modules — PR #273 +- [x] Remove `any` types from API module (`deno/api/`) — PR #274 +- [x] Remove `any` types from frontend — client, plugins, utils, models, components — PR #275 +- [x] Remove `any` types from test files (chat.ts helper, 14 test files, users.ts) — PR #276 +- [x] Fix `style: any` prop in `ActionButton.tsx` — typed as `string` (PR #275) - [ ] Remove `@ts-ignore` comments in `deno/api/files.ts` (5+ instances) - [ ] Standardize Props interface naming @@ -288,7 +291,7 @@ Create standard story template with: ## Notes - Created: 2026-02-06 -- Last updated: 2026-02-08 +- Last updated: 2026-02-09 - Progress: - ✅ **Section 1: Storybook Cleanup - COMPLETE** - PR #249: Config fixes @@ -299,6 +302,16 @@ Create standard story template with: - PR #254: Message story image fix - 🔄 **Section 2: Code Cleanup - IN PROGRESS** - PR #255: Dependency updates (npm packages, @std alignment, ESLint React version) +<<<<<<< HEAD + - PRs #272-276: Remove `any` types across codebase (~120 instances) +======= + - PR #272: Remove `any` types from backend core + - PR #273: Remove `any` types from storage, encryption, config, migrate, tools +<<<<<<< HEAD + - PR #274: Remove `any` types from API module +======= +>>>>>>> origin/dev +>>>>>>> origin/dev - 🔄 **Section 3: Architecture Refactoring - IN PROGRESS** - ✅ 3.7 Documentation: ARCHITECTURE.md, CONVENTIONS.md, 14 ADRs, CLAUDE.md - PR #256: Architecture docs diff --git a/app/src/js/components/contexts/tooltip.tsx b/app/src/js/components/contexts/tooltip.tsx index ef771525..1c017286 100644 --- a/app/src/js/components/contexts/tooltip.tsx +++ b/app/src/js/components/contexts/tooltip.tsx @@ -7,7 +7,7 @@ export type TooltipContextType = { content: React.ReactNode, parent: React.ReactNode | HTMLElement, ) => void; - hide: (p: any) => void; + hide: (p: React.ReactNode | HTMLElement) => void; }; export const TooltipContext = createContext( @@ -67,7 +67,7 @@ export const TooltipProvider = ({ children }: TooltipContextProps) => { [setContent, setPos, setParent], ); - const hide = useCallback((p: any) => { + const hide = useCallback((p: React.ReactNode | HTMLElement) => { if (parent === p) { setParent(null); } diff --git a/app/src/js/components/molecules/ActionButton.tsx b/app/src/js/components/molecules/ActionButton.tsx index d5c39806..95657c21 100644 --- a/app/src/js/components/molecules/ActionButton.tsx +++ b/app/src/js/components/molecules/ActionButton.tsx @@ -7,8 +7,8 @@ import { observer } from "mobx-react-lite"; type ActionButtonProps = { children: React.ReactNode; action: string; - style: any; - payload: any; + style?: string; + payload?: Record; }; export const ActionButton = observer( diff --git a/app/src/js/components/molecules/NavChannels.tsx b/app/src/js/components/molecules/NavChannels.tsx index 4e7f43be..b89c3c0e 100644 --- a/app/src/js/components/molecules/NavChannels.tsx +++ b/app/src/js/components/molecules/NavChannels.tsx @@ -76,7 +76,7 @@ export const NavChannels = observer(({ icon }: NavChannelsProps) => { className={{ active: id === c.id }} key={c.id} icon={icon ?? "hash"} - badge={badges.getForChannel(c.id as any)} + badge={badges.getForChannel(String(c.id))} onClick={() => { if (isMobile()) { hideSidebar(); diff --git a/app/src/js/components/molecules/NavUsers.tsx b/app/src/js/components/molecules/NavUsers.tsx index 7c9f3fef..32f3aa82 100644 --- a/app/src/js/components/molecules/NavUsers.tsx +++ b/app/src/js/components/molecules/NavUsers.tsx @@ -118,7 +118,7 @@ export const NavUserButton = ({ const NavUserContainer = observer( ({ user, badges }: { user: User; badges: ReadReceiptsModel }) => { const app = useApp(); - const channel = app.channels.getDirect(user.id as any); + const channel = app.channels.getDirect(String(user.id)); let navigate = (_path: string) => {}; try { navigate = useNavigate(); @@ -128,11 +128,11 @@ const NavUserContainer = observer( return ( { - const channel = await client.api.putDirectChannel(user.id as any); + const channel = await client.api.putDirectChannel(String(user.id)); if (isMobile()) { hideSidebar(); } @@ -152,7 +152,7 @@ export const NavUsers = observer(() => { {users && users.map((user) => ( diff --git a/app/src/js/components/molecules/UserMention.tsx b/app/src/js/components/molecules/UserMention.tsx index 0b185014..75a2a69d 100644 --- a/app/src/js/components/molecules/UserMention.tsx +++ b/app/src/js/components/molecules/UserMention.tsx @@ -26,7 +26,7 @@ export const UserMentionBase = observer(({ user }: UserMentionBaseProps) => { data-id={user.id} href="#" > - @{user?.name || (user.id as any)} + @{user?.name || String(user.id)} ); }); diff --git a/app/src/js/components/organisms/Search.tsx b/app/src/js/components/organisms/Search.tsx index 1283e86b..c6c840d5 100644 --- a/app/src/js/components/organisms/Search.tsx +++ b/app/src/js/components/organisms/Search.tsx @@ -143,7 +143,7 @@ export const SearchResults = observer(
{ gotoMessage(msg); }} diff --git a/app/src/js/components/pages/ErrorPage.tsx b/app/src/js/components/pages/ErrorPage.tsx index 2361c5a1..6bce314b 100644 --- a/app/src/js/components/pages/ErrorPage.tsx +++ b/app/src/js/components/pages/ErrorPage.tsx @@ -66,7 +66,7 @@ const Container = styled.div` type ErrorPageProps = { title?: string; - debug?: any; + debug?: Record; buttons?: ("retry" | "back" | "home")[]; description?: string | string[]; }; diff --git a/app/src/js/components/pages/Register.tsx b/app/src/js/components/pages/Register.tsx index 27ee4dbe..20992061 100644 --- a/app/src/js/components/pages/Register.tsx +++ b/app/src/js/components/pages/Register.tsx @@ -57,8 +57,9 @@ export const Register = () => { console.log(err); setMsg(err.message); } else { - if ((err as any)?.errorCode === "USER_ALREADY_EXISTS") { - setMsg((err as any).message); + const errObj = err as { errorCode?: string; message?: string }; + if (errObj.errorCode === "USER_ALREADY_EXISTS") { + setMsg(errObj.message ?? "User already exists"); } else { console.log(err); setMsg("Unknown error"); diff --git a/app/src/js/core/client.ts b/app/src/js/core/client.ts index 7627b1d3..aaecaf2a 100644 --- a/app/src/js/core/client.ts +++ b/app/src/js/core/client.ts @@ -20,6 +20,7 @@ export class Client { return this.api.req(...args); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any on(name: string, cb: (e: any) => void) { this.api.on(name, (ev: Event) => { if (ev instanceof CustomEvent) { @@ -32,6 +33,7 @@ export class Client { return this; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any on2(name: string, cb: (e: any) => void) { const handler = (ev: Event) => { if (ev instanceof CustomEvent) { @@ -45,7 +47,7 @@ export class Client { return () => this.api.off(name, handler); } - emit(type: string, data: any) { + emit(type: string, data: unknown) { return this.api.emit(new CustomEvent(type, { detail: data })); } } diff --git a/app/src/js/core/models/files.ts b/app/src/js/core/models/files.ts index 26372d3a..ac1fa312 100644 --- a/app/src/js/core/models/files.ts +++ b/app/src/js/core/models/files.ts @@ -39,7 +39,7 @@ export class FileModel { async dispose() { this.id = undefined; this.clientId = ""; - this.stream = null as any; + this.stream = null as unknown as ReadableStream; this.status = "pending"; this.fileSize = 0; this.fileName = ""; @@ -144,7 +144,7 @@ export class FilesModel { local.patch({ status: "error", progress: 0, error: "unknown error" }); } }); - toJSON(): any { + toJSON(): Array<{ id?: string; clientId: string; fileName: string; fileSize: number; contentType: string }> { return this.list.map((f) => ({ id: f.id, clientId: f.clientId, diff --git a/app/src/js/core/models/input.ts b/app/src/js/core/models/input.ts index e284e206..7904548d 100644 --- a/app/src/js/core/models/input.ts +++ b/app/src/js/core/models/input.ts @@ -43,6 +43,7 @@ export class InputModel { } send = flow(function* (this: InputModel, html: HTMLElement) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const payload: any = fromDom(html); html.innerHTML = ""; payload.attachments = this.files.toJSON(); diff --git a/app/src/js/core/models/message.ts b/app/src/js/core/models/message.ts index e8833cf1..b069017d 100644 --- a/app/src/js/core/models/message.ts +++ b/app/src/js/core/models/message.ts @@ -49,7 +49,7 @@ export class MessageModel implements ViewMessage { favicons: string[]; charset: string; }[]; - parsingErrors?: any[]; + parsingErrors?: Array<{ message: string; nodeAttributes?: Record; nodeName?: string }>; attachments?: Array<{ id: string; fileName: string; diff --git a/app/src/js/core/plugins.ts b/app/src/js/core/plugins.ts index 61ee317e..1bf4745b 100644 --- a/app/src/js/core/plugins.ts +++ b/app/src/js/core/plugins.ts @@ -2,13 +2,13 @@ import { client } from "./client.ts"; declare global { interface Window { - Chat: any; + Chat: typeof plugins; } } -const registry: Record> = {}; +const registry: Record> = {}; const plugins = { - register: (slot: string, data: any) => { + register: (slot: string, data: unknown) => { if (typeof data === "function") { data = data(client); } @@ -16,7 +16,7 @@ const plugins = { [data].flat().forEach((d) => registry[slot].push(d)); }, - get: (slot: string): any => registry[slot] || [], + get: (slot: string): unknown[] => registry[slot] || [], }; window.Chat = plugins; diff --git a/app/src/js/utils.ts b/app/src/js/utils.ts index 6bf65513..7ebc6755 100644 --- a/app/src/js/utils.ts +++ b/app/src/js/utils.ts @@ -32,7 +32,7 @@ export const cn = (...classes: ClassNames[]) => return item; }).flat().filter(Boolean).join(" "); -export const same = (o1: any, o2: any, fields: string[]): boolean => { +export const same = (o1: Record, o2: Record, fields: string[]): boolean => { return fields.every((field) => { return o1 && o2 && o1[field] === o2[field]; }); diff --git a/deno/api/auth.ts b/deno/api/auth.ts index 5c755312..e5731dc5 100644 --- a/deno/api/auth.ts +++ b/deno/api/auth.ts @@ -8,10 +8,15 @@ import * as enc from "@quack/encryption"; import type API from "./mod.ts"; export class ApiError extends Error { - payload: any; + payload: Record; url: string; status: number; - constructor(msg: string, status: number, url: string, payload: any) { + constructor( + msg: string, + status: number, + url: string, + payload: Record, + ) { super(msg); this.status = status; this.url = url; diff --git a/deno/api/files.ts b/deno/api/files.ts index 946b091c..abd8ac58 100644 --- a/deno/api/files.ts +++ b/deno/api/files.ts @@ -55,12 +55,12 @@ export class FilesAPI { delete this.aborts[args.clientId]; resolve(data); }, { once: true }); - xhr.upload.addEventListener("progress", (e: any) => { + xhr.upload.addEventListener("progress", (e: ProgressEvent) => { if (e.lengthComputable) { args.onProgress?.((e.loaded / e.total) * 100); } }); - xhr.addEventListener("error", (e: any) => { + xhr.addEventListener("error", (e: Event) => { delete this.aborts[args.clientId]; reject(e); }, { once: true }); @@ -120,7 +120,7 @@ export class FilesAPI { return new Promise((resolve, reject) => { (async () => { try { - const chunks: any[] = []; + const chunks: BlobPart[] = []; // @ts-ignore This is only for browsers for await (const chunk of stream) { chunks.push(chunk.value); diff --git a/deno/api/messageTypes.ts b/deno/api/messageTypes.ts index 83589a54..9f057ab5 100644 --- a/deno/api/messageTypes.ts +++ b/deno/api/messageTypes.ts @@ -22,7 +22,7 @@ export type MessageBodyButton = { button: string; _action: string; _style: string; - _payload: any; + _payload: Record; }; export type MessageBodyWrap = { wrap: MessageBody }; export type MessageBodyColumn = { column: MessageBody; _width: number }; @@ -101,7 +101,7 @@ export type MessageData = { favicons: string[]; charset: string; }[]; - parsingErrors?: any[]; + parsingErrors?: Array<{ message: string; path?: string }>; attachments?: Array<{ // TODO make this a separate entity id: string; fileName: string; diff --git a/deno/api/mod.ts b/deno/api/mod.ts index d305b853..6bc4dcae 100644 --- a/deno/api/mod.ts +++ b/deno/api/mod.ts @@ -15,7 +15,16 @@ import { FilesAPI } from "./files.ts"; export * from "./types.ts"; -declare const document: any; +export type ApiResponse = { + type: "response"; + status: "ok"; + seqId?: string; + data: Record[]; +}; + +declare const document: { + addEventListener: (type: string, listener: () => void) => void; +} | undefined; const isDeno = typeof window === "undefined"; @@ -36,10 +45,15 @@ async function waitBeforeRetry(retry: number) { } export class ApiError extends Error { - payload: any; + payload: Record; url: string; status: number; - constructor(msg: string, status: number, url: string, payload: any) { + constructor( + msg: string, + status: number, + url: string, + payload: Record, + ) { super(msg); this.status = status; this.url = url; @@ -50,7 +64,7 @@ export class ApiError extends Error { class API extends EventTarget { baseUrl: string; - _http: any; + _http: unknown; _token: string | undefined; userId: string | undefined; @@ -76,7 +90,7 @@ class API extends EventTarget { reconnectTimeout: number | undefined; - set token(value: any) { + set token(value: string | undefined) { if (typeof value === "string" && value.trim() !== "") { this._token = value; this.tokenInit(); @@ -183,7 +197,7 @@ class API extends EventTarget { async fetchWithCredentials( url: string, opts: RequestInit = {}, - ): Promise { + ): Promise { return await this.fetch( `${this.baseUrl}${url}`, this.token @@ -211,11 +225,11 @@ class API extends EventTarget { url: string, opts: { seqId?: string; - mapFn?: (i: any) => any; + mapFn?: (i: Record) => Record; retry?: number; retries?: number; } & RequestInit = {}, - ): Promise { + ): Promise { const retries = opts?.retries ?? 5; const retry = opts?.retry ?? 0; const res = await this.fetchWithCredentials(url, opts); @@ -333,7 +347,7 @@ class API extends EventTarget { ...Object.fromEntries( Object.entries(query).filter(([_, v]) => typeof v !== "undefined"), ), - } as any); + } as Record); return await this.getResource( `/api/channels/${channelId}/messages?${params.toString()}`, ); @@ -439,7 +453,7 @@ class API extends EventTarget { appId?: string; clientId: string; action: string; - payload: any; + payload?: Record; }, ): Promise { const res = await this.fetchWithCredentials(`/api/interactions`, { @@ -449,7 +463,7 @@ class API extends EventTarget { await res.body?.cancel(); } - async sendMessage(msg: Partial): Promise { + async sendMessage(msg: Partial): Promise> { return await new Promise((resolve, reject) => { const data = { ...msg }; let timeoutId: number | null = setTimeout(() => { @@ -489,7 +503,7 @@ class API extends EventTarget { }); } - async sendCommand(cmd: Partial): Promise { + async sendCommand(cmd: Partial): Promise> { const data = { ...cmd }; const res = await this.fetchWithCredentials( "/api/commands/execute", @@ -521,13 +535,13 @@ class API extends EventTarget { case "channels:load": { return this.callApi("/api/channels", { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "channel", ...i }), + mapFn: (i: Record) => ({ type: "channel", ...i }), }); } case "user:getAll": { return this.callApi("/api/users", { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "user", ...i }), + mapFn: (i: Record) => ({ type: "user", ...i }), }); } case "user:get": { @@ -536,7 +550,7 @@ class API extends EventTarget { case "emoji:getAll": { return this.callApi("/api/emojis", { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "emoji", ...i }), + mapFn: (i: Record) => ({ type: "emoji", ...i }), }); } case "channel:create": { @@ -565,6 +579,7 @@ class API extends EventTarget { }, ); + if (createRes instanceof ApiErrorResponse) return createRes; return await this.callApi(`/api/messages/${createRes.data[0].id}`, { method: "GET", }); @@ -599,19 +614,19 @@ class API extends EventTarget { `/api/channels/${msg.channelId}/messages?q=${msg.text}`, { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "search", ...i }), + mapFn: (i: Record) => ({ type: "search", ...i }), }, ); case "readReceipt:getOwn": { return this.callApi("/api/read-receipts", { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "badge", ...i }), + mapFn: (i: Record) => ({ type: "badge", ...i }), }); } case "readReceipt:getChannel": { return this.callApi(`/api/channels/${msg.channelId}/read-receipts`, { seqId: msg.seqId, - mapFn: (i: any) => ({ type: "badge", ...i }), + mapFn: (i: Record) => ({ type: "badge", ...i }), }); } case "readReceipt:update": { diff --git a/deno/config/types.ts b/deno/config/types.ts index 715b74dc..c3d75a17 100644 --- a/deno/config/types.ts +++ b/deno/config/types.ts @@ -8,7 +8,7 @@ export type Config = { port: number; databaseUrl: string; cors: (string | RegExp)[]; - plugins?: ((app: any, core: any) => Promise | any)[]; + plugins?: ((app: unknown, core: unknown) => Promise | void)[]; webhooks?: { url: string; events?: string[]; diff --git a/deno/encryption/mod.ts b/deno/encryption/mod.ts index 75b744f8..f323e4c7 100644 --- a/deno/encryption/mod.ts +++ b/deno/encryption/mod.ts @@ -36,7 +36,7 @@ export function encryptor(jwk: JsonWebKey) { ]); return { - encrypt: async (message: any) => { + encrypt: async (message: unknown) => { const iv = crypto.getRandomValues(new Uint8Array(12)); // GCM uses 12 bytes IV const encoded = new TextEncoder().encode(JSON.stringify(message)); const keyy = await key; @@ -70,7 +70,7 @@ export function encryptor(jwk: JsonWebKey) { }; } export async function encrypt( - message: any, + message: unknown, encryptionKey: JsonWebKey | CryptoKey, ) { const key = importKey(encryptionKey); @@ -88,7 +88,7 @@ export async function encrypt( }; } -export async function decrypt( +export async function decrypt( data: { encrypted: string; _iv: string }, encryptionKey: JsonWebKey | CryptoKey, ): Promise { @@ -291,7 +291,7 @@ export async function prepareRegistration( }; } -export async function decryptSessionSecrets( +export async function decryptSessionSecrets( email: string, password: string, secrets: EncryptedData, diff --git a/deno/migrate/mod.ts b/deno/migrate/mod.ts index 1509b36b..2474773c 100644 --- a/deno/migrate/mod.ts +++ b/deno/migrate/mod.ts @@ -13,7 +13,7 @@ export class Database { databaseUrl: string; - promises: Promise[] = []; + promises: Promise[] = []; connected = false; diff --git a/deno/server/app.ts b/deno/server/app.ts index d6f54b25..6d369a42 100644 --- a/deno/server/app.ts +++ b/deno/server/app.ts @@ -7,9 +7,7 @@ const core = new Core({ }); const http = new HttpInterface(core); await Promise.all( - config.plugins?.map(( - plugin: (app: HttpInterface, core: Core) => Promise | any, - ) => plugin(http, core)) ?? [], + config.plugins?.map((plugin) => plugin(http, core)) ?? [], ); http.onClose(async () => { diff --git a/deno/server/core/bus.ts b/deno/server/core/bus.ts index a1a04f18..dddf8850 100644 --- a/deno/server/core/bus.ts +++ b/deno/server/core/bus.ts @@ -1,12 +1,14 @@ import { EntityId } from "../types.ts"; import { serialize } from "./serializer.ts"; -type Listeners = { [key: string]: ((...args: any[]) => void)[] }; +type BusMessage = Record; +type BusCallback = (msg: BusMessage) => void; +type Listeners = { [key: string]: BusCallback[] }; class Emitter { listeners: Listeners = {}; - on = (ev: string, cb: (...args: any[]) => void) => { + on = (ev: string, cb: BusCallback) => { this.listeners[ev] = this.listeners[ev] ?? []; this.listeners[ev].push(cb); return () => { @@ -14,10 +16,10 @@ class Emitter { }; }; - emit = (ev: string, ...args: any[]) => { + emit = (ev: string, msg: BusMessage) => { (this.listeners[ev] ?? []).forEach((cb) => { try { - cb(...serialize(args)); + cb(serialize(msg)); } catch (e) { console.error(e); } @@ -45,7 +47,11 @@ export class Bus { {}, ); - group = (userIds: (EntityId | string)[], msg: any, senderId?: EntityId) => { + group = ( + userIds: (EntityId | string)[], + msg: BusMessage, + senderId?: EntityId, + ) => { this.internalBus.emit("notif", { ...msg, _target: "group", @@ -57,7 +63,7 @@ export class Bus { }); }; - direct = (userId: EntityId | string, msg: any) => { + direct = (userId: EntityId | string, msg: BusMessage) => { this.internalBus.emit(userId.toString(), { ...msg, _target: "direct" }); this.internalBus.emit("notif", { ...msg, @@ -66,12 +72,12 @@ export class Bus { }); }; - broadcast = (msg: any) => { + broadcast = (msg: BusMessage) => { this.internalBus.emit("all", { ...msg, _target: "broadcast" }); this.internalBus.emit("notif", { ...msg, _target: "broadcast" }); }; - on = (userId: EntityId | string, cb: (...args: any[]) => void) => { + on = (userId: EntityId | string, cb: BusCallback) => { const a = this.internalBus.on(userId.toString(), cb); const b = this.internalBus.on("all", cb); return () => { @@ -80,8 +86,8 @@ export class Bus { }; }; - notif = (msg: any) => + notif = (msg: BusMessage) => this.internalBus.emit("notif", { ...msg, _target: "notif" }); - onNotif = (cb: (...args: any[]) => void) => this.internalBus.on("notif", cb); + onNotif = (cb: BusCallback) => this.internalBus.on("notif", cb); } diff --git a/deno/server/core/command.ts b/deno/server/core/command.ts index 295cc3ee..e78791f2 100644 --- a/deno/server/core/command.ts +++ b/deno/server/core/command.ts @@ -2,21 +2,7 @@ import * as v from "valibot"; import { EntityId } from "../types.ts"; import type { Core } from "./core.ts"; import { AppError } from "./errors.ts"; - -function serialize(obj: A): any { - if (obj instanceof EntityId) { - return obj.toString(); - } - if (Array.isArray(obj)) { - return obj.map(serialize); - } - if (typeof obj === "object") { - for (const key in obj) { - obj[key] = serialize(obj[key]); - } - } - return obj; -} +import { serialize } from "./serializer.ts"; export type Definition< T extends string, @@ -69,10 +55,12 @@ export function createCommand< internal() { return exec(body, core); }, - then( - onfulfilled: (value: void | EntityId | string | null) => any, - onrejected: (reason: any) => any, - ) { + then( + onfulfilled: ( + value: void | EntityId | string | null, + ) => TResult1 | PromiseLike, + onrejected: (reason: unknown) => TResult2 | PromiseLike, + ): PromiseLike { return exec(body, core).then((r) => serialize(r)).then( onfulfilled, onrejected, @@ -94,10 +82,11 @@ export type CommandDirectory = { export function buildCommandCollection( events: T, ): CommandDirectory { - return events.reduce((acc, curr) => { - acc[curr.type] = curr; - return acc; - }, {} as any); + const result: Record = {}; + for (const curr of events) { + result[curr.type] = curr; + } + return result as CommandDirectory; } export type EventFrom = T extends Command diff --git a/deno/server/core/core.ts b/deno/server/core/core.ts index 6bd74a2e..5b656d36 100644 --- a/deno/server/core/core.ts +++ b/deno/server/core/core.ts @@ -125,9 +125,20 @@ export class Core { } } - dispatch = (evt: EventFrom) => ( - (commands[evt.type] as any).handler(evt.body, this) - ); + dispatch = (evt: EventFrom) => { + // Type assertion needed: evt.type and evt.body are correlated through + // the discriminated union, but TypeScript can't prove it for indexed access + type AnyCommand = typeof commands[keyof typeof commands]; + const cmd = commands[evt.type] as AnyCommand; + // deno-lint-ignore no-explicit-any + return (cmd.handler as ( + body: any, + core: Core, + ) => ReturnType)( + evt.body, + this, + ); + }; close = async () => { this.events.dispatch({ diff --git a/deno/server/core/message/create.ts b/deno/server/core/message/create.ts index 8bdf7001..d3769d69 100644 --- a/deno/server/core/message/create.ts +++ b/deno/server/core/message/create.ts @@ -5,7 +5,7 @@ import { AccessDenied, InvalidMessage, ResourceNotFound } from "../errors.ts"; import { flatten } from "./flatten.ts"; import { ChannelType, EntityId } from "../../types.ts"; -function filterUndefined(data: any) { +function filterUndefined(data: Record) { return Object.fromEntries( Object.entries(data).filter(([, v]) => v !== undefined), ); @@ -79,7 +79,7 @@ export default createCommand({ userId: msg.userId, links: msg.links, mentions: msg.mentions, - attachments: msg.attachments?.map((file: any) => ({ + attachments: msg.attachments?.map((file) => ({ id: file.id, fileName: file.fileName, contentType: file.contentType, @@ -104,9 +104,8 @@ export default createCommand({ type: "channel:join", body: { channelId: msg.channelId.toString(), - userIds: msg.mentions.filter((m: any) => - !channel.users.some((u) => u.eq(m)) - ).map((u) => u.toString()), + userIds: msg.mentions.filter((m) => !channel.users.some((u) => u.eq(m))) + .map((u) => u.toString()), }, }).internal(); diff --git a/deno/server/core/query.ts b/deno/server/core/query.ts index e78a5919..f36563c1 100644 --- a/deno/server/core/query.ts +++ b/deno/server/core/query.ts @@ -6,7 +6,7 @@ import { serialize } from "./serializer.ts"; export type Event = { type: string; - body: any; + body: unknown; }; export type Definition = { type: string; @@ -38,7 +38,10 @@ export function createQuery( async internal() { return await exec(body); }, - then(onfulfilled: (value: B) => any, onrejected: (reason: any) => any) { + then( + onfulfilled: (value: B) => TResult1 | PromiseLike, + onrejected: (reason: unknown) => TResult2 | PromiseLike, + ): PromiseLike { return exec(body).then((ret) => serialize(ret)).then( onfulfilled, onrejected, diff --git a/deno/server/core/serializer.ts b/deno/server/core/serializer.ts index 30692136..3e86d4d4 100644 --- a/deno/server/core/serializer.ts +++ b/deno/server/core/serializer.ts @@ -1,16 +1,21 @@ import { EntityId } from "../types.ts"; -export function serialize(obj: A): any { +function recursiveSerialize(obj: unknown): unknown { if (obj instanceof EntityId) { return obj.toString(); } if (Array.isArray(obj)) { - return obj.map(serialize); + return obj.map(recursiveSerialize); } - if (typeof obj === "object") { - for (const key in obj) { - obj[key] = serialize(obj[key]); + if (typeof obj === "object" && obj !== null) { + const record = obj as Record; + for (const key in record) { + record[key] = recursiveSerialize(record[key]); } } return obj; } + +export function serialize(obj: A): A { + return recursiveSerialize(obj) as A; +} diff --git a/deno/server/core/webhooks.ts b/deno/server/core/webhooks.ts index 11d306a3..b28562a1 100644 --- a/deno/server/core/webhooks.ts +++ b/deno/server/core/webhooks.ts @@ -7,15 +7,15 @@ export class Webhooks { this.core.bus.onNotif(this.handleEvent.bind(this)); } - async handleEvent(event: any) { + async handleEvent(event: Record) { for (const webhook of (this.config?.webhooks ?? [])) { - if (!webhook.events || webhook.events.includes(event.type)) { + if (!webhook.events || webhook.events.includes(event.type as string)) { await this.send(webhook, event); } } } - async send(webhook: Webhook, event: any) { + async send(webhook: Webhook, event: Record) { try { const body = JSON.stringify({ type: event.type, event }); const res = await fetch(webhook.url, { diff --git a/deno/server/infra/repo/channelRepo.ts b/deno/server/infra/repo/channelRepo.ts index b2154f00..42282eba 100644 --- a/deno/server/infra/repo/channelRepo.ts +++ b/deno/server/infra/repo/channelRepo.ts @@ -9,7 +9,7 @@ export class ChannelRepo extends Repo { override makeQuery(data: ChannelQuery) { const { userId, users, usersCount, ...rest } = serialize(data); const query = { ...rest }; - const userQuery: any = {}; + const userQuery: Record = {}; if (userId) userQuery["$elemMatch"] = { $eq: userId }; if (users) userQuery["$all"] = users; if (usersCount) userQuery["$size"] = usersCount; diff --git a/deno/server/infra/repo/serializer.ts b/deno/server/infra/repo/serializer.ts index 0dd1f3ab..6de128c5 100644 --- a/deno/server/infra/repo/serializer.ts +++ b/deno/server/infra/repo/serializer.ts @@ -1,7 +1,8 @@ import { EntityId } from "../../types.ts"; import { ObjectId } from "./db.ts"; -function recursiveDeserialize(obj: any): any { +// deno-lint-ignore no-explicit-any +function recursiveDeserialize(obj: unknown): any { if (obj instanceof EntityId) { return EntityId.from(obj); } @@ -11,41 +12,46 @@ function recursiveDeserialize(obj: any): any { if (Array.isArray(obj)) { return obj.map(recursiveDeserialize); } - if (typeof obj === "object") { - for (const key in obj) { - obj[key] = recursiveDeserialize(obj[key]); + if (typeof obj === "object" && obj !== null) { + const record = obj as Record; + for (const key in record) { + record[key] = recursiveDeserialize(record[key]); } - if (obj && obj._id) { - obj.id = obj._id; - delete obj._id; + if (record._id) { + record.id = record._id; + delete record._id; } } return obj; } -export function deserialize(data: any) { +// deno-lint-ignore no-explicit-any +export function deserialize(data: unknown): any { return recursiveDeserialize(data); } -function recursiveSerialize(obj: any): any { +// deno-lint-ignore no-explicit-any +function recursiveSerialize(obj: unknown): any { if (obj instanceof EntityId) { return new ObjectId(obj.value); } if (Array.isArray(obj)) { return obj.map(recursiveSerialize); } - if (typeof obj === "object") { - for (const key in obj) { - obj[key] = recursiveSerialize(obj[key]); + if (typeof obj === "object" && obj !== null) { + const record = obj as Record; + for (const key in record) { + record[key] = recursiveSerialize(record[key]); } - if (obj && obj.id) { - obj._id = obj.id; - delete obj.id; + if (record.id) { + record._id = record.id; + delete record.id; } } return obj; } -export function serialize(data: any) { +// deno-lint-ignore no-explicit-any +export function serialize(data: unknown): any { return recursiveSerialize(data); } diff --git a/deno/server/infra/repo/userRepo.ts b/deno/server/infra/repo/userRepo.ts index 4d1c4c39..a009f1d4 100644 --- a/deno/server/infra/repo/userRepo.ts +++ b/deno/server/infra/repo/userRepo.ts @@ -23,7 +23,10 @@ export class UserRepo extends Repo { ); } - async upgrade(query: UserQuery, data: { publicKey: any; secrets: Secret }) { + async upgrade( + query: UserQuery, + data: { publicKey: JsonWebKey; secrets: Secret }, + ) { const { db } = await this.connect(); await db.collection(this.COLLECTION) .updateOne( diff --git a/deno/server/inter/cli/mod.ts b/deno/server/inter/cli/mod.ts index 5b87dd19..ab3634bc 100644 --- a/deno/server/inter/cli/mod.ts +++ b/deno/server/inter/cli/mod.ts @@ -3,9 +3,15 @@ import { Command } from "@cliffy/command"; const run = new Command() .arguments("") .description("Runs the chat server.") - .action((options: any, source: string, destination?: string) => { - console.log("clone command called"); - }); + .action( + ( + _options: Record, + source: string, + _destination?: string, + ) => { + console.log("clone command called"); + }, + ); await new Command() .name("chat") diff --git a/deno/server/inter/http/mod.ts b/deno/server/inter/http/mod.ts index 2a2878d3..604b3f14 100644 --- a/deno/server/inter/http/mod.ts +++ b/deno/server/inter/http/mod.ts @@ -33,7 +33,7 @@ export class HttpInterface extends Planigale { schema.addKeyword({ keyword: "requireAny", type: "object", - validate: (keys: string[], data: any) => { + validate: (keys: string[], data: Record) => { if (keys.some((key) => key in data)) { return true; } diff --git a/deno/server/inter/http/routes/__tests__/chat.ts b/deno/server/inter/http/routes/__tests__/chat.ts index 118d3769..a9c42920 100644 --- a/deno/server/inter/http/routes/__tests__/chat.ts +++ b/deno/server/inter/http/routes/__tests__/chat.ts @@ -5,9 +5,11 @@ import { Repository } from "../../../../infra/mod.ts"; import { ensureUser } from "./users.ts"; import { Channel, + Emoji, EntityId, Message, ReplaceEntityId, + User, } from "../../../../types.ts"; import { AsyncLocalStorage } from "node:async_hooks"; import API, { LoginError, Result, UserSession } from "@quack/api"; @@ -19,6 +21,19 @@ export type RegistrationRequest = { email: string; }; +type CommandResult = { + status: string; + json: Record; + channelId: string; + events: SSESource | null; +}; + +type Attachment = { + id: string; + fileName: string; + contentType: string; +}; + // deno-lint-ignore ban-types type Arg = T | ((chat: Chat) => T); const asyncLocalStorage = new AsyncLocalStorage<{ instances: Chat[] }>(); @@ -46,11 +61,12 @@ export class Chat { currentStep = 0; - state: any = {}; + // deno-lint-ignore no-explicit-any + state: Record = {}; - steps: any[] = []; + steps: Array<() => Promise> = []; - cleanup: any[] = []; + cleanup: Array<() => Promise> = []; appVersion = "client-version"; @@ -134,7 +150,7 @@ export class Chat { data: Arg< { token: string; email: string; password: string; oldPassword: string } >, - test?: (session: Result) => Promise | any, + test?: (session: Result) => Promise | void, ) { this.steps.push(async () => { const resetData = this.arg(data); @@ -158,7 +174,9 @@ export class Chat { return this; } - nextEvent(fn: (event: any, chat: Chat) => any) { + nextEvent( + fn: (event: Record, chat: Chat) => Promise | void, + ) { this.steps.push(async () => { const { event } = await this.eventSource?.next() || {}; await fn(JSON.parse(event?.data || "{}"), this); @@ -169,7 +187,7 @@ export class Chat { login( email = "admin", password = "123", - test?: (session: Result) => Promise | any, + test?: (session: Result) => Promise | void, ) { this.steps.push(async () => { await ensureUser(this.repo, email); @@ -183,7 +201,10 @@ export class Chat { return this; } - checkToken(tokenData: Arg, test?: (body: any) => Promise | any) { + checkToken( + tokenData: Arg, + test?: (body: Record) => Promise | void, + ) { this.steps.push(async () => { const token = this.arg(tokenData); const ret = await this.api.auth.checkRegistrationToken({ token }); @@ -194,7 +215,7 @@ export class Chat { register( data: RegistrationRequest, - test?: (body: any) => Promise | any, + test?: (body: Record) => Promise | void, ) { this.steps.push(async () => { const body = await this.api.auth.register(data); @@ -212,7 +233,7 @@ export class Chat { createChannel( channelData: Arg>>, - test?: (channel: Channel, chat: Chat) => Promise | any, + test?: (channel: Channel, chat: Chat) => Promise | void, ) { let channelId: string; this.steps.push(async () => { @@ -248,7 +269,7 @@ export class Chat { test?: ( channel: ReplaceEntityId, chat: Chat, - ) => Promise | any, + ) => Promise | void, ) { this.steps.push(async () => { const { userId } = this.arg(data); @@ -278,7 +299,7 @@ export class Chat { test?: ( channel: ReplaceEntityId, chat: Chat, - ) => Promise | any, + ) => Promise | void, ) { this.steps.push(async () => { const { userId } = this.arg(data); @@ -326,7 +347,7 @@ export class Chat { } getChannel( - fn: (channel: ReplaceEntityId, chat: Chat) => Promise | any, + fn: (channel: ReplaceEntityId, chat: Chat) => Promise | void, ) { this.steps.push(async () => { const res = await this.agent.request() @@ -339,7 +360,7 @@ export class Chat { return this; } - getEmojis(fn: (emojis: any[]) => Promise) { + getEmojis(fn: (emojis: Emoji[]) => Promise | void) { this.steps.push(async () => { const res = await this.agent.request() .get("/api/emojis") @@ -351,7 +372,7 @@ export class Chat { return this; } - getConfig(fn: (config: any) => Promise) { + getConfig(fn: (config: Record) => Promise | void) { this.steps.push(async () => { const res = await this.agent.request() .get("/api/profile/config") @@ -363,7 +384,7 @@ export class Chat { return this; } - getChannels(fn: (channels: Channel[]) => Promise | any) { + getChannels(fn: (channels: Channel[]) => Promise | void) { this.steps.push(async () => { const res = await this.agent.request() .get("/api/channels") @@ -375,7 +396,9 @@ export class Chat { return this; } - getUsers(fn: (users: any[], chat: Chat) => Promise) { + getUsers( + fn: (users: User[], chat: Chat) => Promise | void, + ) { this.steps.push(async () => { const res = await this.agent.request() .get("/api/users") @@ -389,7 +412,7 @@ export class Chat { getUser( userId: string | ((chat: Chat) => string), - fn: (user: any) => Promise, + fn: (user: User) => Promise | void, ) { this.steps.push(async () => { const id = typeof userId === "function" ? userId(this) : userId; @@ -405,7 +428,10 @@ export class Chat { getMessages( queryData: Arg<{ parentId?: string | null }> = {}, - test?: (messages: any[], chat: Chat) => Promise | any, + test?: ( + messages: Record[], + chat: Chat, + ) => Promise | void, ) { this.steps.push(async () => { const { parentId } = this.arg(queryData); @@ -429,7 +455,7 @@ export class Chat { test?: ( message: ReplaceEntityId, chat: Chat, - ) => Promise | any, + ) => Promise | void, ) { this.steps.push(async () => { const message = this.arg(messageData); @@ -453,7 +479,7 @@ export class Chat { channelId?: string; parentId?: string; clientId: string; - payload?: any; + payload?: Record; action: string; }>, ) { @@ -487,7 +513,10 @@ export class Chat { } getChannelReadReceipts( - fn: (receipts: any[], chat: Chat) => Promise | any, + fn: ( + receipts: Record[], + chat: Chat, + ) => Promise | void, ) { this.steps.push(async () => { const res = await this.agent.request() @@ -500,7 +529,12 @@ export class Chat { return this; } - getReadReceipts(fn: (receipts: any[], chat: Chat) => Promise | any) { + getReadReceipts( + fn: ( + receipts: Record[], + chat: Chat, + ) => Promise | void, + ) { this.steps.push(async () => { const res = await this.agent.request() .get("/api/read-receipts") @@ -514,7 +548,10 @@ export class Chat { updateReadReceipts( messageId: string | ((chat: Chat) => string), - test?: (receipt: any, chat: Chat) => Promise | any, + test?: ( + receipt: Record, + chat: Chat, + ) => Promise | void, ) { this.steps.push(async () => { const res = await this.agent.request() @@ -537,8 +574,8 @@ export class Chat { executeCommand( command: string, - attachments: any[], - test?: (...args: any) => any, + attachments: Attachment[], + test?: (result: CommandResult) => Promise | void, ) { this.steps.push(async () => { if (!this.channelId) { @@ -577,7 +614,12 @@ export class Chat { return this; } - getPinnedMessages(fn: (messages: any[], chat: Chat) => Promise | any) { + getPinnedMessages( + fn: ( + messages: Record[], + chat: Chat, + ) => Promise | void, + ) { this.steps.push(async () => { const res = await this.agent.request() .get(`/api/channels/${this.channelId}/messages?pinned=true`) @@ -600,7 +642,7 @@ export class Chat { return this; } - step(test: (chat: Chat) => any) { + step(test: (chat: Chat) => Promise | void) { this.steps.push(async () => { await test(this); }); @@ -612,7 +654,7 @@ export class Chat { return this; } - async then(resolve: (self?: any) => any, reject: (e: unknown) => any) { + async then(resolve: (self?: void) => void, reject: (e: unknown) => void) { let cleanupStart = false; try { while (this.steps[this.currentStep]) { diff --git a/deno/server/inter/http/routes/__tests__/users.ts b/deno/server/inter/http/routes/__tests__/users.ts index 163e4a09..26a4d89f 100644 --- a/deno/server/inter/http/routes/__tests__/users.ts +++ b/deno/server/inter/http/routes/__tests__/users.ts @@ -5,6 +5,7 @@ import * as enc from "@quack/encryption"; export const ensureUser = async ( repo: Repository, email: string, + // deno-lint-ignore no-explicit-any rest: any = {}, ) => { const user = await repo.user.get({ email }); diff --git a/deno/server/inter/http/routes/auth/__tests__/session.test.ts b/deno/server/inter/http/routes/auth/__tests__/session.test.ts index f2b129be..1cc6c016 100644 --- a/deno/server/inter/http/routes/auth/__tests__/session.test.ts +++ b/deno/server/inter/http/routes/auth/__tests__/session.test.ts @@ -24,15 +24,17 @@ Deno.test("POST /auth/session - wrong params", async () => { const body = await res.json(); assertEquals( - body.errors?.map((e: any) => e?.params?.missingProperty).sort(), + body.errors?.map((e: Record) => + (e?.params as Record)?.missingProperty + ).sort(), ["email", "password"], ); }); Deno.test("Login/logout", async (t) => { - let token: any = null; - let userId: any = null; - let key: any = null; + let token: string | null = null; + let userId: string | null = null; + let key: string | null = null; await ensureUser(repo, "admin"); await t.step("POST /auth/session - Create session", async () => { @@ -92,8 +94,8 @@ Deno.test("Login/logout", async (t) => { }); Deno.test("Login/logout - cookies", async (t) => { - let token: any = null; - let userId: any = null; + let token: string | null = null; + let userId: string | null = null; await t.step("POST /auth/session - Create session", async () => { const credentials = await enc.prepareCredentials("admin", "123"); diff --git a/deno/server/inter/http/routes/channel/__tests__/channels.test.ts b/deno/server/inter/http/routes/channel/__tests__/channels.test.ts index 80efe028..4de96700 100644 --- a/deno/server/inter/http/routes/channel/__tests__/channels.test.ts +++ b/deno/server/inter/http/routes/channel/__tests__/channels.test.ts @@ -27,7 +27,7 @@ Deno.test("/api/channels", async () => { .login("admin") .connectSSE() .createChannel({ name: "test-channel-creation" }) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "channel"); assertEquals(event.name, "test-channel-creation"); }) @@ -59,7 +59,7 @@ Deno.test("/api/channels - channel with description", async () => { name: "test-channel-with-description", description: "This is a test channel description", }) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "channel"); assertEquals(event.name, "test-channel-with-description"); assertEquals(event.description, "This is a test channel description"); @@ -84,7 +84,7 @@ Deno.test("/api/channels - other user receives notification about channel", asyn users: [member.userIdR], }); await member - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "channel"); assertEquals(event.name, "test-channel-creation-2"); }) diff --git a/deno/server/inter/http/routes/channel/__tests__/direct.test.ts b/deno/server/inter/http/routes/channel/__tests__/direct.test.ts index fe4a5408..1ff63ee0 100644 --- a/deno/server/inter/http/routes/channel/__tests__/direct.test.ts +++ b/deno/server/inter/http/routes/channel/__tests__/direct.test.ts @@ -25,7 +25,7 @@ Deno.test("/api/channels/direct/:userId", async () => { .nextEvent((event, chat) => { assertEquals(event.type, "message"); assertEquals(event.flat, "hello"); - chat.channelId = event.channelId; + chat.channelId = event.channelId as string; chat.state.directChannelId = event.channelId; }) .getMessages({}, (messages) => { diff --git a/deno/server/inter/http/routes/channel/postChannel.ts b/deno/server/inter/http/routes/channel/postChannel.ts index eef079cd..ad6c61f6 100644 --- a/deno/server/inter/http/routes/channel/postChannel.ts +++ b/deno/server/inter/http/routes/channel/postChannel.ts @@ -39,7 +39,7 @@ export default (core: Core) => }, }); const channel = await core.channel.get({ - id: channelId, + id: channelId!, userId: req.state.user.id, }); return Res.json(channel); diff --git a/deno/server/inter/http/routes/channel/putDirect.ts b/deno/server/inter/http/routes/channel/putDirect.ts index 1eabfa36..cafca278 100644 --- a/deno/server/inter/http/routes/channel/putDirect.ts +++ b/deno/server/inter/http/routes/channel/putDirect.ts @@ -26,7 +26,7 @@ export default (core: Core) => }, }); const channel = await core.channel.get({ - id: channelId, + id: channelId!, userId: req.state.user.id, }); return Res.json(channel); diff --git a/deno/server/inter/http/routes/commands/__tests__/commands.test.ts b/deno/server/inter/http/routes/commands/__tests__/commands.test.ts index 175c12f5..04574e96 100644 --- a/deno/server/inter/http/routes/commands/__tests__/commands.test.ts +++ b/deno/server/inter/http/routes/commands/__tests__/commands.test.ts @@ -29,7 +29,10 @@ Deno.test("command /echo ", async () => assertEquals(event.type, "message"); assert(event.clientId, "Event should have clientId"); assertEquals(event.flat, "Hello World!!"); - assertEquals(event.message.text, "Hello World!!"); + assertEquals( + (event.message as Record).text, + "Hello World!!", + ); assertEquals(event.channelId, chat.channelId); }) .end(), @@ -37,7 +40,7 @@ Deno.test("command /echo ", async () => Deno.test("command /emoji ", async () => await Chat.test(app, { type: "handler" }, async (agent) => { - const state: any = {}; + const state: Record = {}; try { await Chat.init(repo, agent) .login("admin") @@ -52,11 +55,11 @@ Deno.test("command /emoji ", async () => ], async ({ channelId }) => { state.channelId = channelId; }) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "emoji"); assertEquals(event.shortname, ":party-parrot:"); }) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "message"); assert(event.clientId, "Event should have clientId"); assertEquals(event.flat, "Emoji :party-parrot: created"); @@ -82,12 +85,14 @@ Deno.test("command /invite", async () => { .createChannel({ name: "test-commands-invite" }) .connectSSE() .executeCommand("/invite", [], ({ json }) => { - url = json.data; + url = json.data as string; }) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "message"); assert(event.clientId, "Event should have clientId"); - const m = event.flat.match("(https?://.*/invite/[0-9a-f]{32})"); + const m = (event.flat as string).match( + "(https?://.*/invite/[0-9a-f]{32})", + ); assert(m, "Result should contain invitation link"); assertEquals(m[1], url); }) @@ -108,7 +113,7 @@ Deno.test("command /avatar", async () => { contentType: "image/gif", }, ]) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "user"); assertEquals(event.avatarFileId, "party-parrot"); }) @@ -129,8 +134,8 @@ Deno.test("command /version", async () => { .nextEvent((event) => { assertEquals(event.type, "message"); assert(event.clientId, "Event should have clientId"); - assertEquals(event.flat.includes("server-version"), true); - assertEquals(event.flat.includes("client-version"), true); + assertEquals((event.flat as string).includes("server-version"), true); + assertEquals((event.flat as string).includes("client-version"), true); }) .end(); }); @@ -146,10 +151,10 @@ Deno.test("command /help", async () => { .nextEvent((event) => { assertEquals(event.type, "message"); assert(event.clientId, "Event should have clientId"); - assertEquals(event.flat.includes("/avatar"), true); - assertEquals(event.flat.includes("/emoji"), true); - assertEquals(event.flat.includes("/invite"), true); - assertEquals(event.flat.includes("/version"), true); + assertEquals((event.flat as string).includes("/avatar"), true); + assertEquals((event.flat as string).includes("/emoji"), true); + assertEquals((event.flat as string).includes("/invite"), true); + assertEquals((event.flat as string).includes("/version"), true); }) .end(); }); @@ -169,7 +174,7 @@ Deno.test("command /leave", async () => { .nextEvent((event, chat) => { assertEquals(event.type, "channel"); assert( - !event.users.find((u: any) => u === chat.userId), + !(event.users as string[]).find((u) => u === chat.userId), "Updated channel should not contain user", ); }) diff --git a/deno/server/inter/http/routes/emojis/__tests__/emojis.test.ts b/deno/server/inter/http/routes/emojis/__tests__/emojis.test.ts index d619d9cb..0071d32a 100644 --- a/deno/server/inter/http/routes/emojis/__tests__/emojis.test.ts +++ b/deno/server/inter/http/routes/emojis/__tests__/emojis.test.ts @@ -43,7 +43,7 @@ Deno.test("Adding emojis and listing them", async () => { fileName: "smile.png", contentType: "image/png", }]) - .nextEvent((event: any) => { + .nextEvent((event) => { assertEquals(event.type, "emoji"); assertEquals(event.shortname, ":smile:"); }) diff --git a/deno/server/inter/http/routes/interactions/__tests__/interaction.test.ts b/deno/server/inter/http/routes/interactions/__tests__/interaction.test.ts index 47034bb2..59cc96a7 100644 --- a/deno/server/inter/http/routes/interactions/__tests__/interaction.test.ts +++ b/deno/server/inter/http/routes/interactions/__tests__/interaction.test.ts @@ -2,7 +2,7 @@ import { Agent } from "@planigale/testing"; import { assertEquals } from "@std/assert"; import { createApp } from "../../__tests__/app.ts"; import { Chat } from "../../__tests__/chat.ts"; -import { MessageInteractionEvent } from "../../../../../events.ts"; +import type { Event, MessageInteractionEvent } from "../../../../../events.ts"; import { EntityId } from "../../../../../types.ts"; const { app, repo, core } = createApp(); @@ -16,7 +16,7 @@ Deno.test("POST /api/interactions - dispatching interactions", async (t) => { .createChannel({ name: "test-messages-interactions" }); const { promise, resolve, reject } = Promise.withResolvers(); (async () => { - const event: any = await new Promise((resolve) => + const event: Event = await new Promise((resolve) => core.events.once(resolve) ); if (event.type !== "message:interaction") { @@ -50,7 +50,7 @@ Deno.test("POST /api/interactions - graceful shutdown", async (t) => { .login("admin") .createChannel({ name: "test-messages-interactions" }); for (let i = 0; i < 5; i++) { - const { promise, resolve } = Promise.withResolvers(); + const { promise, resolve } = Promise.withResolvers(); core.events.once(resolve); await admin.interaction({ action: "test", clientId: "clientId" }); await promise; diff --git a/deno/server/inter/http/routes/messages/__tests__/format.test.ts b/deno/server/inter/http/routes/messages/__tests__/format.test.ts index f385c041..a15c4c83 100644 --- a/deno/server/inter/http/routes/messages/__tests__/format.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/format.test.ts @@ -18,7 +18,11 @@ Deno.test("Check all validations for message field", async (t) => { name: "messages-formating-check", users: [EntityId.from(userId)], }, async (channelId) => { - const testPart = async (status: number, name: string, message: any) => + const testPart = async ( + status: number, + name: string, + message: Record | Record[], + ) => await t.step(name, async () => await agent.request() .post(`/api/channels/${channelId}/messages/`) diff --git a/deno/server/inter/http/routes/messages/__tests__/messages.test.ts b/deno/server/inter/http/routes/messages/__tests__/messages.test.ts index 93bf9964..556f25b8 100644 --- a/deno/server/inter/http/routes/messages/__tests__/messages.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/messages.test.ts @@ -427,7 +427,11 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 3); - assertEquals(body.map((m: any) => m.flat), ["t2", "t1", "t0"]); + assertEquals(body.map((m: Record) => m.flat), [ + "t2", + "t1", + "t0", + ]); }); await t.step("GET /api/channels/:channelId/messages - limit", async () => { @@ -438,7 +442,10 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 2); - assertEquals(body.map((m: any) => m.flat), ["t2", "t1"]); + assertEquals(body.map((m: Record) => m.flat), [ + "t2", + "t1", + ]); }); await t.step( @@ -455,7 +462,10 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 2); - assertEquals(body.map((m: any) => m.flat), ["t1", "t0"]); + assertEquals(body.map((m: Record) => m.flat), [ + "t1", + "t0", + ]); }, ); await t.step("GET /api/channels/:channelId/messages - before", async () => { @@ -470,7 +480,7 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 1); - assertEquals(body.map((m: any) => m.flat), ["t0"]); + assertEquals(body.map((m: Record) => m.flat), ["t0"]); }); await t.step("GET /api/channels/:channelId/messages - after", async () => { const res = await agent.request() @@ -484,7 +494,10 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 2); - assertEquals(body.map((m: any) => m.flat), ["t2", "t1"]); + assertEquals(body.map((m: Record) => m.flat), [ + "t2", + "t1", + ]); }); await t.step("GET /api/channels/:channelId/messages - pinend", async () => { const res = await agent.request() @@ -494,7 +507,7 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 1); - assertEquals(body.map((m: any) => m.flat), ["t1"]); + assertEquals(body.map((m: Record) => m.flat), ["t1"]); }); await t.step("GET /api/channels/:channelId/messages - offset", async () => { const res = await agent.request() @@ -504,7 +517,7 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 1); - assertEquals(body.map((m: any) => m.flat), ["t2"]); + assertEquals(body.map((m: Record) => m.flat), ["t2"]); }); await t.step("GET /api/channels/:channelId/messages - search", async () => { const res = await agent.request() @@ -514,7 +527,7 @@ Deno.test("Messages history", async (t) => { const body = await res.json(); assertEquals(body.length, 1); - assertEquals(body.map((m: any) => m.flat), ["t1"]); + assertEquals(body.map((m: Record) => m.flat), ["t1"]); }); }); await agent.close(); diff --git a/deno/server/inter/http/routes/messages/__tests__/notifications.test.ts b/deno/server/inter/http/routes/messages/__tests__/notifications.test.ts index cdadaf27..e5211079 100644 --- a/deno/server/inter/http/routes/messages/__tests__/notifications.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/notifications.test.ts @@ -13,7 +13,7 @@ Deno.test("webhook should be sent", async (t) => { }, ], }); - const { promise, resolve } = Promise.withResolvers(); + const { promise, resolve } = Promise.withResolvers>(); const srv = Deno.serve({ port: 8123, handler: async (req) => { @@ -34,7 +34,7 @@ Deno.test("webhook should be sent", async (t) => { const event = await promise; assertEquals(event.type, "message"); - assertEquals(event.event.flat, "test"); + assertEquals((event.event as Record).flat, "test"); await srv.shutdown(); await app.close(); @@ -72,7 +72,7 @@ Deno.test("webhook should be called once", async (t) => { }, ], }); - const { promise, resolve } = Promise.withResolvers(); + const { promise, resolve } = Promise.withResolvers>(); const srv = Deno.serve({ port: 8123, handler: async (req) => { @@ -96,7 +96,7 @@ Deno.test("webhook should be called once", async (t) => { assertEquals(calls, 1); assertEquals(event.type, "message"); - assertEquals(event.event.flat, "test"); + assertEquals((event.event as Record).flat, "test"); await srv.shutdown(); await app.close(); diff --git a/deno/server/inter/http/routes/messages/__tests__/pinning.test.ts b/deno/server/inter/http/routes/messages/__tests__/pinning.test.ts index 49095954..bf7f42b2 100644 --- a/deno/server/inter/http/routes/messages/__tests__/pinning.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/pinning.test.ts @@ -23,26 +23,26 @@ Deno.test("Pinning other user messsage", async (t) => { flat: "Hello", message: { text: "Hello" }, clientId: "hello", - }, (msg: any) => { - pinMessageId = msg.id; + }, (msg) => { + pinMessageId = msg.id as string; }); await t.step("pinning message", async () => { await member.pinMessage({ messageId: pinMessageId }) - .getPinnedMessages((messages: any) => { + .getPinnedMessages((messages) => { assertEquals(messages.length, 1); assertEquals(messages[0].id, pinMessageId); }); - await admin.getPinnedMessages((messages: any) => { + await admin.getPinnedMessages((messages) => { assertEquals(messages.length, 1); assertEquals(messages[0].id, pinMessageId); }); }); await t.step("unpinning message by other user", async () => { await admin.pinMessage({ messageId: pinMessageId, pinned: false }) - .getPinnedMessages((messages: any) => { + .getPinnedMessages((messages) => { assertEquals(messages.length, 0); }); - await member.getPinnedMessages((messages: any) => { + await member.getPinnedMessages((messages) => { assertEquals(messages.length, 0); }); }); diff --git a/deno/server/inter/http/routes/messages/__tests__/react.test.ts b/deno/server/inter/http/routes/messages/__tests__/react.test.ts index 9f704db9..21d44abb 100644 --- a/deno/server/inter/http/routes/messages/__tests__/react.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/react.test.ts @@ -28,9 +28,13 @@ Deno.test("PUT /api/messages/:messageId/react - sending reacts to messages", asy messageId: state.messageId, reaction: ":thumbsup:", })) - .getMessages({}, (messages: any) => { - assertEquals(messages[0].reactions.length, 1); - assertEquals(messages[0].reactions[0], { + .getMessages({}, (messages) => { + const reactions = messages[0].reactions as Record< + string, + unknown + >[]; + assertEquals(reactions.length, 1); + assertEquals(reactions[0], { userId: admin.userId, reaction: ":thumbsup:", }); @@ -38,7 +42,7 @@ Deno.test("PUT /api/messages/:messageId/react - sending reacts to messages", asy }); await t.step("checking reactions by second user", async () => { - await member.getMessages({}, (messages: any, { state }) => { + await member.getMessages({}, (messages, { state }) => { state.messageId = messages[0].id; }); }); @@ -54,17 +58,21 @@ Deno.test("PUT /api/messages/:messageId/react - sending reacts to messages", asy messageId: state.messageId, reaction: ":thumbsup:", })) - .getMessages({}, (messages: any) => { - assertEquals(messages[0].reactions.length, 3); - assertEquals(messages[0].reactions[0], { + .getMessages({}, (messages) => { + const reactions = messages[0].reactions as Record< + string, + unknown + >[]; + assertEquals(reactions.length, 3); + assertEquals(reactions[0], { userId: admin.userId, reaction: ":thumbsup:", }); - assertEquals(messages[0].reactions[1], { + assertEquals(reactions[1], { userId: member.userId, reaction: ":thumbsdown:", }); - assertEquals(messages[0].reactions[2], { + assertEquals(reactions[2], { userId: member.userId, reaction: ":thumbsup:", }); @@ -77,13 +85,17 @@ Deno.test("PUT /api/messages/:messageId/react - sending reacts to messages", asy messageId: state.messageId, reaction: ":thumbsup:", })) - .getMessages({}, (messages: any) => { - assertEquals(messages[0].reactions.length, 2); - assertEquals(messages[0].reactions[0], { + .getMessages({}, (messages) => { + const reactions = messages[0].reactions as Record< + string, + unknown + >[]; + assertEquals(reactions.length, 2); + assertEquals(reactions[0], { userId: admin.userId, reaction: ":thumbsup:", }); - assertEquals(messages[0].reactions[1], { + assertEquals(reactions[1], { userId: member.userId, reaction: ":thumbsdown:", }); @@ -120,10 +132,11 @@ Deno.test("PUT /api/messages/:messageId/react - SSR about reactions", async (t) messageId: state.messageId, reaction: ":thumbsup:", })); - await member.nextEvent((event: any) => { + await member.nextEvent((event) => { + const reactions = event.reactions as Record[]; assertEquals(event.type, "message"); - assertEquals(event.reactions.length, 1); - assertEquals(event.reactions[0], { + assertEquals(reactions.length, 1); + assertEquals(reactions[0], { userId: admin.userId, reaction: ":thumbsup:", }); @@ -135,9 +148,10 @@ Deno.test("PUT /api/messages/:messageId/react - SSR about reactions", async (t) messageId: state.messageId, reaction: ":thumbsup:", })); - await member.nextEvent((event: any) => { + await member.nextEvent((event) => { + const reactions = event.reactions as Record[]; assertEquals(event.type, "message"); - assertEquals(event.reactions.length, 0); + assertEquals(reactions.length, 0); }); }); } finally { diff --git a/deno/server/inter/http/routes/messages/__tests__/threads.test.ts b/deno/server/inter/http/routes/messages/__tests__/threads.test.ts index 82545fcc..218f20a1 100644 --- a/deno/server/inter/http/routes/messages/__tests__/threads.test.ts +++ b/deno/server/inter/http/routes/messages/__tests__/threads.test.ts @@ -15,7 +15,7 @@ Deno.test("sending messages to threads", async (t) => { }) .sendMessage({ flat: "Hello", - }, (msg: any, { state }) => { + }, (msg, { state }) => { state.parentId = msg.id; }) .sendMessage({ @@ -23,15 +23,15 @@ Deno.test("sending messages to threads", async (t) => { }) .sendMessage(({ state }) => ({ flat: "msg1", parentId: state.parentId })) .sendMessage(({ state }) => ({ flat: "msg2", parentId: state.parentId })) - .getMessages({ parentId: null }, (messages: any) => { + .getMessages({ parentId: null }, (messages) => { assertEquals(messages.length, 3); - assertEquals(messages[1].thread.length, 2); + assertEquals((messages[1].thread as unknown[]).length, 2); }) .getMessages( ({ state }) => ({ parentId: state.parentId }), - (messages: any, { state }) => { + (messages, { state }) => { assertEquals(messages.length, 3); - assertEquals(messages[0].thread.length, 2); + assertEquals((messages[0].thread as unknown[]).length, 2); assertEquals(messages[0].id, state.parentId); }, ) diff --git a/deno/server/inter/http/routes/messages/create.ts b/deno/server/inter/http/routes/messages/create.ts index fd62de26..d56502d1 100644 --- a/deno/server/inter/http/routes/messages/create.ts +++ b/deno/server/inter/http/routes/messages/create.ts @@ -54,7 +54,7 @@ export default (core: Core) => body: { ...req.body, userId, channelId }, }); - const msg = await core.message.get({ userId, messageId: id }); + const msg = await core.message.get({ userId, messageId: id! }); return Response.json(msg); }, }); diff --git a/deno/server/inter/http/routes/mobile/notifications.ts b/deno/server/inter/http/routes/mobile/notifications.ts index e92d88ba..60fdf225 100644 --- a/deno/server/inter/http/routes/mobile/notifications.ts +++ b/deno/server/inter/http/routes/mobile/notifications.ts @@ -42,7 +42,8 @@ export default (core: Core) => }, HEARTBEAT_INTERVAL_MS); // Subscribe to bus events for this user - const off = core.bus.on(userId, async (msg: BusMessage) => { + const off = core.bus.on(userId, async (raw) => { + const msg = raw as BusMessage; // Only process message events for notifications if (msg.type !== "message") { return; diff --git a/deno/server/inter/http/routes/profile/__tests__/profile.test.ts b/deno/server/inter/http/routes/profile/__tests__/profile.test.ts index 50cf32b4..198c66c9 100644 --- a/deno/server/inter/http/routes/profile/__tests__/profile.test.ts +++ b/deno/server/inter/http/routes/profile/__tests__/profile.test.ts @@ -23,7 +23,7 @@ Deno.test("GET /api/profile/config - getConfig", async () => { await admin.login("admin") .createChannel({ name: "Test" }); await admin.executeCommand("/main", []) - .getConfig(async (body: any) => { + .getConfig(async (body) => { assertEquals(body.appVersion, "1.2.3"); assertEquals(body.mainChannelId, admin.channelId); }) diff --git a/deno/server/inter/http/routes/readReceipt/__tests__/readReceipt.test.ts b/deno/server/inter/http/routes/readReceipt/__tests__/readReceipt.test.ts index 697a5858..ed56ec08 100644 --- a/deno/server/inter/http/routes/readReceipt/__tests__/readReceipt.test.ts +++ b/deno/server/inter/http/routes/readReceipt/__tests__/readReceipt.test.ts @@ -1,4 +1,4 @@ -import { assertEquals } from "@std/assert"; +import { assert, assertEquals } from "@std/assert"; import { Chat } from "../../__tests__/chat.ts"; import { createApp } from "../../__tests__/app.ts"; @@ -19,10 +19,9 @@ Deno.test("/api/channels/:channelId/read-receipts", async () => }, (msg, { state }) => { state.messageId = msg.id; }) - .getChannelReadReceipts((receipts: any, self) => { - const receipt = receipts.find((r: any) => - r.channelId === self.channelId - ); + .getChannelReadReceipts((receipts, self) => { + const receipt = receipts.find((r) => r.channelId === self.channelId); + assert(receipt, "Receipt should exist"); assertEquals(receipt.count, 0); assertEquals(receipt.lastMessageId, self.state.messageId); }) @@ -51,12 +50,12 @@ Deno.test("/api/channels/:channelId/read-receipts - SSE", async () => await admin.connectSSE(); await member - .getMessages({}, async (messages: any, { state, channelId }) => { + .getMessages({}, async (messages, { state, channelId }) => { state.messageId = messages[0].id; }) .updateReadReceipts(({ state }) => state.messageId); - await admin.nextEvent((event: any) => { + await admin.nextEvent((event) => { assertEquals(event.type, "readReceipt"); assertEquals(event.lastMessageId, member.state.messageId); assertEquals(event.userId, member.userId); @@ -88,7 +87,7 @@ Deno.test("/api/read-receipts", async () => { clientId: "test2", }); await member - .getMessages({}, async (messages: any, { state }) => { + .getMessages({}, async (messages, { state }) => { state.messageId = messages[0].id; }) .updateReadReceipts(({ state }) => state.messageId); @@ -102,11 +101,10 @@ Deno.test("/api/read-receipts", async () => { message: { text: "Hello" }, clientId: "test4", }); - await member.getReadReceipts((receipts: any) => { + await member.getReadReceipts((receipts) => { assertEquals(receipts.length, 1); - const receipt = receipts.find((r: any) => - r.channelId === member.channelId - ); + const receipt = receipts.find((r) => r.channelId === member.channelId); + assert(receipt, "Receipt should exist"); assertEquals(receipt.count, 2); }); } finally { diff --git a/deno/server/inter/http/routes/users/__tests__/registration.test.ts b/deno/server/inter/http/routes/users/__tests__/registration.test.ts index 0d8b61c9..4e6a2ac1 100644 --- a/deno/server/inter/http/routes/users/__tests__/registration.test.ts +++ b/deno/server/inter/http/routes/users/__tests__/registration.test.ts @@ -21,8 +21,8 @@ Deno.test("POST /api/users - user creation flow", async (t) => { .sendMessage({ flat: "secret" }); await t.step("creating invite", async () => { - await admin.executeCommand("/invite", [], ({ json }: any) => { - url = json.data; + await admin.executeCommand("/invite", [], ({ json }) => { + url = json.data as string; }); const m = url.match(/https?:\/\/.*\/invite\/(.*)$/); assert(m); @@ -31,8 +31,8 @@ Deno.test("POST /api/users - user creation flow", async (t) => { await t.step("creating second invite", async () => { let url2: string = ""; - await admin.executeCommand("/invite", [], ({ json }: any) => { - url2 = json.data; + await admin.executeCommand("/invite", [], ({ json }) => { + url2 = json.data as string; }); const m = url2.match(/https?:\/\/.*\/invite\/(.*)$/); assert(m); @@ -66,7 +66,7 @@ Deno.test("POST /api/users - user creation flow", async (t) => { assert(session.secrets._iv); }) .openChannel("user-invite-test") - .getMessages({}, (msgs: any[]) => { + .getMessages({}, (msgs) => { assertEquals(msgs[0].flat, "secret"); }); }); diff --git a/deno/server/inter/http/routes/users/__tests__/users.test.ts b/deno/server/inter/http/routes/users/__tests__/users.test.ts index 6bad3001..2a059e06 100644 --- a/deno/server/inter/http/routes/users/__tests__/users.test.ts +++ b/deno/server/inter/http/routes/users/__tests__/users.test.ts @@ -29,7 +29,7 @@ Deno.test("GET /api/users/:userId - getUser with an id and alias", async () => { }) .getUser(({ state }) => state.member.id, async (user: User) => { assert(user.name === "Member"); - assert((user as any).secrets === undefined); + assert((user as Record).secrets === undefined); assert(user.publicKey); }) .end(); @@ -46,8 +46,8 @@ Deno.test("GET /api/users - getAllUsers", async () => { const userNames = users.map((u: User) => u.name); assert(userNames.includes("Admin")); assert(userNames.includes("Member")); - assert((users[0] as any).password === undefined); - assert((users[1] as any).password === undefined); + assert((users[0] as Record).password === undefined); + assert((users[1] as Record).password === undefined); }) .end(); }); @@ -63,8 +63,8 @@ Deno.test("POST /api/users - user creation flow", async () => { await admin.login("admin") .createChannel({ name: "user-invite-test" }) .sendMessage({ flat: "secret" }) - .executeCommand("/invite", [], ({ json }: any) => { - url = json.data; + .executeCommand("/invite", [], ({ json }) => { + url = json.data as string; }); const m = url.match(/https?:\/\/.*\/invite\/(.*)$/); assert(m); @@ -78,7 +78,7 @@ Deno.test("POST /api/users - user creation flow", async () => { }) .login("jack", "test123") .openChannel("user-invite-test") - .getMessages({}, (msgs: any[]) => { + .getMessages({}, (msgs) => { assertEquals(msgs[0].flat, "secret"); }) .end(); diff --git a/deno/server/inter/http/routes/users/create.ts b/deno/server/inter/http/routes/users/create.ts index 7e4aba53..17475e47 100644 --- a/deno/server/inter/http/routes/users/create.ts +++ b/deno/server/inter/http/routes/users/create.ts @@ -56,7 +56,7 @@ export default (core: Core) => secrets: req.body.secrets, }, }); - const user: DbUser | null = await core.user.get({ id: createdId }); + const user: DbUser | null = await core.user.get({ id: createdId! }); if (!user) { throw new InternalServerError( new Error("User not created, but no error thrown"), diff --git a/deno/storage/src/core/mod.ts b/deno/storage/src/core/mod.ts index ba4fa690..8432b626 100644 --- a/deno/storage/src/core/mod.ts +++ b/deno/storage/src/core/mod.ts @@ -10,8 +10,18 @@ type ScalingOpts = { height?: number; }; +interface FileService { + upload( + stream: ReadableStream, + options: FileOpts, + ): Promise; + get(id: string): Promise; + remove(id: string): Promise; + exists(id: string): Promise; +} + class Files { - _sharp: any; + _sharp: typeof sharp | null | undefined = undefined; async getSharp() { if (this._sharp === undefined) { try { @@ -28,7 +38,7 @@ class Files { static getFileId = (id: string, width = 0, height = 0) => `${id}-${width}x${height}`; - private service: any; + private service!: FileService; constructor(config: Config) { this.init(config.storage); diff --git a/deno/storage/src/core/streams.ts b/deno/storage/src/core/streams.ts index ba8a6d5b..72327526 100644 --- a/deno/storage/src/core/streams.ts +++ b/deno/storage/src/core/streams.ts @@ -1,43 +1,34 @@ import { Readable } from "node:stream"; -interface ListenerInterface { - data: (chunk: any) => void; - end: (chunk: any) => void; - close: (err: any) => void; - error: (err: any) => void; -} - export function toWebStream(nodeStream: Readable) { let destroyed = false; - const listeners = {} as ListenerInterface; + // deno-lint-ignore no-explicit-any + const listeners: Record void> = {}; - function start(controller: any) { + function start(controller: ReadableStreamDefaultController) { listeners.data = onData; listeners.end = onData; listeners.end = onDestroy; listeners.close = onDestroy; listeners.error = onDestroy; for (const name in listeners) { - nodeStream.on(name, listeners[name as keyof ListenerInterface]); + nodeStream.on(name, listeners[name]); } nodeStream.pause(); - function onData(chunk: any) { + function onData(chunk: Uint8Array) { if (destroyed) return; controller.enqueue(new Uint8Array(chunk)); nodeStream.pause(); } - function onDestroy(err: any) { + function onDestroy(err?: Error) { if (destroyed) return; destroyed = true; for (const name in listeners) { - nodeStream.removeListener( - name, - listeners[name as keyof ListenerInterface], - ); + nodeStream.removeListener(name, listeners[name]); } if (err) controller.error(err); @@ -54,10 +45,7 @@ export function toWebStream(nodeStream: Readable) { destroyed = true; for (const name in listeners) { - nodeStream.removeListener( - name, - listeners[name as keyof ListenerInterface], - ); + nodeStream.removeListener(name, listeners[name]); } nodeStream.push(null); @@ -75,7 +63,7 @@ class NodeReadable extends Readable { private reader: ReadableStreamDefaultReader; - private pendingRead?: Promise; + private pendingRead?: Promise>; constructor(stream: ReadableStream) { super(); diff --git a/deno/tools/cache.ts b/deno/tools/cache.ts index 0a4a71cb..974d6075 100644 --- a/deno/tools/cache.ts +++ b/deno/tools/cache.ts @@ -1,6 +1,6 @@ import { mergeRanges, Range } from "./range.ts"; -export class CacheEntry extends Range { +export class CacheEntry extends Range { data: T; timestamp: number; @@ -10,7 +10,7 @@ export class CacheEntry extends Range { this.timestamp = new Date().getTime(); } - static sort(repo: CacheEntry[]) { + static sort(repo: CacheEntry[]) { return [...repo].sort((a, b) => a.from - b.from); } @@ -24,7 +24,7 @@ export type CacheQuery = { to?: number; }; -export class Cache { +export class Cache { repo: CacheEntry[] = []; merge = (a: CacheEntry, b: CacheEntry): CacheEntry => ( diff --git a/desktop/src-tauri/icons/icon.ico b/desktop/src-tauri/icons/icon.ico index a802c5980e90f5ac86524e4b69954c2a51cc14b8..a12977d3520b7b6d30a41eea5c849adb867db9a0 100644 GIT binary patch literal 24621 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 QDoA$I5^uZye{&W72fk|Ec>n+a literal 59329 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 From 2d2d90817a5d04ad24f819344f50a0e2e31ee74e Mon Sep 17 00:00:00 2001 From: Mateusz Date: Thu, 19 Feb 2026 18:21:41 +0100 Subject: [PATCH 4/6] feat(desktop): add server profile picker with MRU grid --- desktop/src/index.html | 322 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 287 insertions(+), 35 deletions(-) diff --git a/desktop/src/index.html b/desktop/src/index.html index bfc6a565..70b58d7a 100644 --- a/desktop/src/index.html +++ b/desktop/src/index.html @@ -4,6 +4,8 @@ Quack

Quack

-

Enter your Quack server URL to connect

- -
- +

Choose a server

+ + +
+
+ +
+ + + Add server +
+
+
+ + +
+ +
+
+ + +
+
From 234da79aaa47a2c9b4e04480c9805e68c4c80de2 Mon Sep 17 00:00:00 2001 From: Mateusz Date: Fri, 20 Feb 2026 16:57:58 +0100 Subject: [PATCH 5/6] fix(desktop): persist servers via global store, reopen on dock click --- desktop/src-tauri/src/lib.rs | 13 +++++++++++-- desktop/src/index.html | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index bd1bda9c..64d963e5 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -87,6 +87,15 @@ pub fn run() { Ok(()) }) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .build(tauri::generate_context!()) + .expect("error while building tauri application") + .run(|app_handle, event| { + // On macOS, clicking the dock icon fires Reopen — show the window + if let tauri::RunEvent::Reopen { .. } = event { + if let Some(window) = app_handle.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + }); } diff --git a/desktop/src/index.html b/desktop/src/index.html index 70b58d7a..79bc5f93 100644 --- a/desktop/src/index.html +++ b/desktop/src/index.html @@ -274,7 +274,7 @@

Quack

async function loadServers() { try { if (window.__TAURI__) { - const { load } = await import('https://unpkg.com/@tauri-apps/plugin-store/dist/index.min.mjs'); + const { load } = window.__TAURI__.store; store = await load('config.json'); // Migrate legacy single-URL key From 597a297335327f2b991e83a428f028f48deb50bf Mon Sep 17 00:00:00 2001 From: Mateusz Date: Fri, 20 Feb 2026 17:05:49 +0100 Subject: [PATCH 6/6] fix(desktop): gate RunEvent::Reopen behind macos cfg --- desktop/src-tauri/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 64d963e5..ee6bfe13 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -91,11 +91,14 @@ pub fn run() { .expect("error while building tauri application") .run(|app_handle, event| { // On macOS, clicking the dock icon fires Reopen — show the window + #[cfg(target_os = "macos")] if let tauri::RunEvent::Reopen { .. } = event { if let Some(window) = app_handle.get_webview_window("main") { let _ = window.show(); let _ = window.set_focus(); } } + #[cfg(not(target_os = "macos"))] + let _ = (app_handle, event); }); }