diff --git a/.SRCINFO b/.SRCINFO deleted file mode 100644 index a3f8fe9..0000000 --- a/.SRCINFO +++ /dev/null @@ -1,30 +0,0 @@ -pkgbase = emerald-legacy-launcher - pkgdesc = FOSS, cross-platform launcher for Minecraft Legacy Console Edition - pkgver = 1.0.0 - pkgrel = 1 - url = https://github.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher - arch = x86_64 - license = GPL-3.0 - makedepends = git - makedepends = openssl - makedepends = appmenu-gtk-module - makedepends = libappindicator-gtk3 - makedepends = librsvg - makedepends = cargo - makedepends = pnpm - makedepends = nodejs - depends = cairo - depends = desktop-file-utils - depends = gdk-pixbuf2 - depends = glib2 - depends = gtk3 - depends = hicolor-icon-theme - depends = libsoup - depends = pango - depends = webkit2gtk-4.1 - optdepends = discord: Discord RPC support - provides = emerald-legacy-launcher - source = emerald-legacy-launcher::git+https://github.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher#branch=main - sha256sums = SKIP - -pkgname = emerald-legacy-launcher diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml deleted file mode 100644 index 995228c..0000000 --- a/.github/workflows/experimental.yml +++ /dev/null @@ -1,313 +0,0 @@ -name: "experimental" -on: - workflow_dispatch: - -jobs: - build-goldmapper: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: install mingw toolchain - run: | - sudo apt-get update - sudo apt-get install -y gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - name: build GoldMapper - run: | - pnpm install - pnpm goldmapper - - uses: actions/upload-artifact@v4 - with: - name: goldmapper - path: | - src-tauri/resources/GoldMapperLib.dll - src-tauri/resources/GoldMapperLauncher.exe - src-tauri/resources/SDL2.dll - - build-tauri: - needs: [build-goldmapper] - strategy: - fail-fast: false - matrix: - include: - - platform: "macos-latest" - args: "--target aarch64-apple-darwin" - artifact-name: macos-aarch64 - - platform: "macos-latest" - args: "--target x86_64-apple-darwin" - artifact-name: macos-x86_64 - - platform: "ubuntu-24.04" - args: "--bundles deb,rpm" - artifact-name: linux - - platform: "ubuntu-24.04-arm" - args: "--target aarch64-unknown-linux-gnu --bundles deb,rpm" - artifact-name: linux-arm64 - - platform: "windows-latest" - args: "" - artifact-name: windows - - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - - name: install dependencies (ubuntu only) - if: startsWith(matrix.platform, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf libudev-dev - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: install Rust stable - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || matrix.platform == 'ubuntu-24.04-arm' && 'aarch64-unknown-linux-gnu' || '' }} - - - name: Rust cache - uses: swatinem/rust-cache@v2 - with: - workspaces: "./src-tauri -> target" - - - name: install frontend dependencies - run: pnpm install - - - name: build Tauri app - run: pnpm tauri build ${{ matrix.args }} - env: - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - - - name: run macOS postbuild - run: pnpm post-build:macos - if: matrix.platform == 'macos-latest' - - - name: Create PKG with post-install script (macOS only) - if: matrix.platform == 'macos-latest' - run: | - mkdir -p pkg_temp/scripts - cp scripts/postinstall.sh pkg_temp/scripts/ - MACOS_BUNDLE_DIR=$(find src-tauri/target -path "*/release/bundle/macos" -type d | head -n 1) - APP_PATH=$(find "$MACOS_BUNDLE_DIR" -name "*.app" -type d | head -n 1) - if [ -z "$APP_PATH" ]; then - echo "No .app found in $MACOS_BUNDLE_DIR" - exit 1 - fi - APP_NAME=$(basename "$APP_PATH") - pkgbuild --root "$APP_PATH/.." \ - --install-location /Applications \ - --scripts pkg_temp/scripts \ - --identifier "com.emerald.legacy" \ - --version "1.0.0" \ - "Emerald-Legacy-Launcher.pkg" - mv "Emerald-Legacy-Launcher.pkg" "$MACOS_BUNDLE_DIR/" - - - name: upload build artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact-name }} - path: | - src-tauri/target/**/release/bundle/**/* - - build-flatpak: - needs: [build-goldmapper] - runs-on: ubuntu-latest - container: - image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08 - options: --privileged - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - name: sleep for 10 seconds - run: sleep 10 - - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 - with: - bundle: Emerald.Legacy.Launcher.flatpak - manifest-path: flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.yml - cache-key: flatpak-builder-${{ github.sha }} - - name: upload flatpak artifact - uses: actions/upload-artifact@v4 - with: - name: flatpak - path: Emerald.Legacy.Launcher.flatpak - - build-appimage: - needs: [build-goldmapper] - runs-on: ubuntu-latest - container: - image: archlinux:latest - steps: - - name: Bootstrap keyring and git - run: | - pacman -Syu --noconfirm archlinux-keyring - pacman -S --noconfirm --needed git - - - uses: actions/checkout@v4 - with: - submodules: true - - - uses: actions/cache@v4 - with: - path: | - src-tauri/target - node_modules - /var/cache/pacman/pkg - key: arch-${{ hashFiles('src-tauri/Cargo.lock', 'pnpm-lock.yaml') }} - restore-keys: arch- - - - name: Install build dependencies - run: | - pacman -S --noconfirm --needed \ - base-devel wget zsync nodejs patchelf \ - cargo cargo-tauri \ - gtk3 libayatana-appindicator webkit2gtk-4.1 glib-networking librsvg \ - xorg-server-xvfb - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Build deb with tauri - run: | - pnpm install - cargo-tauri build --bundles deb --config '{"bundle":{"createUpdaterArtifacts":false},"build":{"beforeBuildCommand":"pnpm build"}}' - - - name: Extract deb into /usr - run: | - cd src-tauri/target/release/bundle/deb - ar x ./*.deb - tar -xf data.tar.* - cp -a usr/. /usr/ - - - name: Build AppImage - run: | - cd pkg/AppImage - chmod +x ./AppImage.sh - ./AppImage.sh - - - uses: actions/upload-artifact@v4 - with: - name: appimage - path: pkg/AppImage/dist/*.AppImage - - build-android: - runs-on: ubuntu-latest - needs: [build-goldmapper] - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: setup Java 17 - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: "17" - - - name: setup Android SDK - uses: android-actions/setup-android@v4 - - name: install Android SDK components - run: | - sdkmanager --install "platforms;android-36" "build-tools;36.0.0" "ndk;28.2.13676358" - yes | sdkmanager --licenses - sudo apt-get install -y glslang-tools - - - name: install Rust stable with android target - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-linux-android - - - name: Rust cache - uses: swatinem/rust-cache@v2 - with: - workspaces: "./src-tauri -> target" - - - name: install frontend dependencies - run: pnpm install - - - name: download android bundled assets - run: pnpm android:assets - - - name: restore gradle wrapper jar - run: | - VER=$(sed -n 's/.*gradle-\([0-9][0-9.]*\)-bin\.zip.*/\1/p' src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties) - curl -fL -o src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar \ - "https://raw.githubusercontent.com/gradle/gradle/v${VER}/gradle/wrapper/gradle-wrapper.jar" - - - name: set up android signing keystore - env: - ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} - ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} - run: | - printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > src-tauri/gen/android/app/release.keystore - cat > src-tauri/gen/android/app/key.properties <> $GITHUB_OUTPUT - echo "body<> "$GITHUB_OUTPUT" - cat RELEASE_NOTES.md >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - build-goldmapper: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: install mingw toolchain - run: | - sudo apt-get update - sudo apt-get install -y gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - name: build GoldMapper - run: | - pnpm install - pnpm goldmapper - - uses: actions/upload-artifact@v4 - with: - name: goldmapper - path: | - src-tauri/resources/GoldMapperLib.dll - src-tauri/resources/GoldMapperLauncher.exe - src-tauri/resources/SDL2.dll - - publish-tauri: - needs: [get-version, build-goldmapper] - permissions: - contents: write - strategy: - fail-fast: false - matrix: - include: - - platform: "macos-latest" - args: "--target aarch64-apple-darwin" - - platform: "macos-latest" - args: "--target x86_64-apple-darwin" - - platform: "ubuntu-24.04" - args: "--bundles deb,rpm" - - platform: "ubuntu-24.04-arm" - args: "--target aarch64-unknown-linux-gnu --bundles deb,rpm" - - platform: "windows-latest" - args: "" - - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - - name: install dependencies (ubuntu only) - if: startsWith(matrix.platform, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf libudev-dev - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: install Rust stable - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || matrix.platform == 'ubuntu-24.04-arm' && 'aarch64-unknown-linux-gnu' || '' }} - - - name: Rust cache - uses: swatinem/rust-cache@v2 - with: - workspaces: "./src-tauri -> target" - - - name: install frontend dependencies - run: pnpm install - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - with: - tagName: v__VERSION__ - releaseName: "Emerald v__VERSION__" - releaseBody: ${{ needs.get-version.outputs.body }} - releaseDraft: true - prerelease: false - uploadUpdaterJson: true - args: ${{ matrix.args }} - - build-appimage: - needs: [build-goldmapper] - runs-on: ubuntu-latest - container: - image: archlinux:latest - steps: - - name: Bootstrap keyring and git - run: | - pacman -Syu --noconfirm archlinux-keyring - pacman -S --noconfirm --needed git - - - uses: actions/checkout@v4 - with: - submodules: true - - - uses: actions/cache@v4 - with: - path: | - src-tauri/target - node_modules - /var/cache/pacman/pkg - key: arch-${{ hashFiles('src-tauri/Cargo.lock', 'pnpm-lock.yaml') }} - restore-keys: arch- - - - name: Install build dependencies - run: | - pacman -S --noconfirm --needed \ - base-devel wget zsync nodejs patchelf \ - cargo cargo-tauri \ - gtk3 libayatana-appindicator webkit2gtk-4.1 glib-networking librsvg \ - xorg-server-xvfb - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Build deb with tauri - run: | - pnpm install - cargo-tauri build --bundles deb --config '{"bundle":{"createUpdaterArtifacts":false},"build":{"beforeBuildCommand":"pnpm build"}}' - - - name: Extract deb into /usr - run: | - cd src-tauri/target/release/bundle/deb - ar x ./*.deb - tar -xf data.tar.* - cp -a usr/. /usr/ - - - name: Build AppImage - run: | - cd pkg/AppImage - chmod +x ./AppImage.sh - ./AppImage.sh - - - uses: actions/upload-artifact@v4 - with: - name: appimage - path: pkg/AppImage/dist/*.AppImage* #neo: *.AppImage* because .zsync as well - - build-android: - runs-on: ubuntu-latest - needs: [build-goldmapper] - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: download GoldMapper - uses: actions/download-artifact@v4 - with: - name: goldmapper - path: src-tauri/resources - - - name: setup Java 17 - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: "17" - - - name: setup Android SDK - uses: android-actions/setup-android@v4 - - - name: install Android SDK components - run: | - sdkmanager --install "platforms;android-36" "build-tools;36.0.0" "ndk;28.2.13676358" - yes | sdkmanager --licenses - sudo apt-get install -y glslang-tools - - - name: install Rust stable with android target - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-linux-android - - - name: Rust cache - uses: swatinem/rust-cache@v2 - with: - workspaces: "./src-tauri -> target" - - - name: install frontend dependencies - run: pnpm install - - - name: download android bundled assets - run: pnpm android:assets - - - name: restore gradle wrapper jar - run: | - VER=$(sed -n 's/.*gradle-\([0-9][0-9.]*\)-bin\.zip.*/\1/p' src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties) - curl -fL -o src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar \ - "https://raw.githubusercontent.com/gradle/gradle/v${VER}/gradle/wrapper/gradle-wrapper.jar" - - - name: set up android signing keystore - env: - ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} - ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} - run: | - printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > src-tauri/gen/android/app/release.keystore - cat > src-tauri/gen/android/app/key.properties < Exceptions to this rule may apply depending on the severity of the bug, provided that the code is clearly commented as a hack with a relevant `// :` comment. - -### Don't submit code written by AI. - -Submitting code to this repository authored by generative AI tools (LLMs, agentic coding tools, etc...) is strictly forbidden. Pull requests that are clearly vibe-coded or written by an LLM will be closed. - -> **Rationale:** Contributors are expected to both fully understand the code that they write **and** have the necessary skills to *maintain it*. Opening PRs containing code that you did not write yourself more often than not fails to meet either of these expectations, therefore it is disallowed. diff --git a/Casks/lce-emerald-launcher.rb b/Casks/lce-emerald-launcher.rb deleted file mode 100644 index 999ebce..0000000 --- a/Casks/lce-emerald-launcher.rb +++ /dev/null @@ -1,18 +0,0 @@ -cask "lce-emerald-launcher" do - version "1.6.1" - sha256 intel: "dd86c3f63088585f71ab94acd7c3e3ec0b535fc06ef71e7770741e08fe60782f", - arm: "e2e6c50a5b0b847ed7c857ab8a4ae421fa8666096f3c9fa8bb216f21639dcfd2" - - url "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/download/v#{version}/LCE.Emerald.Launcher_#{version}_#{arch}.dmg" - name "LCE Emerald Launcher" - desc "Minecraft Legacy Console Edition Launcher" - homepage "https://github.com/LCE-Hub/LCE-Emerald-Launcher" - - app "LCE Emerald Launcher/LCE Emerald Launcher.app" - - zap trash: [ - "~/Library/Application Support/com.emerald.legacy", - "~/Library/Preferences/com.emerald.legacy.plist", - "~/Library/Saved Application State/com.emerald.legacy.savedState", - ] -end diff --git a/Formula/lce-emerald-launcher.rb b/Formula/lce-emerald-launcher.rb deleted file mode 100644 index 53e5ac3..0000000 --- a/Formula/lce-emerald-launcher.rb +++ /dev/null @@ -1,19 +0,0 @@ -class LceEmeraldLauncher < Formula - desc "Minecraft Legacy Console Edition Launcher" - homepage "https://github.com/LCE-Hub/LCE-Emerald-Launcher-cask" - url "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/download/v#{version}/LCE.Emerald.Launcher_#{version}_amd64.AppImage" - sha256 "3f135df96014e6bf83ced13a89ba2ec4599532104e60aea97c45d1d246de62f2" - version "1.6.1" - license "GPL-3.0-only" - - depends_on :linux - - def install - # Rename and install the AppImage - bin.install "LCE.Emerald.Launcher_#{version}_amd64.AppImage" => "lce-emerald-launcher" - end - - test do - assert_predicate bin/"lce-emerald-launcher", :exist? - end -end diff --git a/README.md b/README.md index a18c0f4..d9f6f5c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +> [!IMPORTANT] +> This branch is for **Project Radium**, a rewrite of the Emerald Launcher in C++ with SDL3 and it's own UI system. +
LCE Emerald Launcher Logo

LCE Emerald Launcher

diff --git a/RELEASE_ARTWORK.png b/RELEASE_ARTWORK.png deleted file mode 100644 index 44dd3ed..0000000 Binary files a/RELEASE_ARTWORK.png and /dev/null differ diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md deleted file mode 100644 index a49b776..0000000 --- a/RELEASE_NOTES.md +++ /dev/null @@ -1,25 +0,0 @@ -![Release Artwork](https://raw.githubusercontent.com/LCE-Hub/LCE-Emerald-Launcher/refs/heads/main/RELEASE_ARTWORK.png) - -- Fix title bar and panorama not showing on setup -- **Partnership with LapboardMC!** -- **Removed LCEOnline Client, LCEOnline functionality is built into Emerald** -- Fix audio skipping bug on Windows -- Gentoo, Nix flakes and Homebrew support -- **Xbox 360, PS3 and Java -> LCE world importing support (beta!)** -- Proper Discord RPC shutdown -- Remove click effects when disabling animations -- **FULL Android Port powered by our own DiamondRuntime for running the game!** -- Fix neoLegacy downloading issue -- **A lot of UI polish (thanks piebot!)** -- Add 2 default capes -- Add more default skins -- **Emerald Arguments.Schema support!** -- **Partnership with Amythest LCE** -- Fix Slim skins rendering in-launcher -- Randomize splash texts -- **Partnership with Project Lost Legacy (soon!)** -- Add Player Head to Discord RPC -- Make skin face inwards instead of outwards -- Game crash log viewer support! -- **Intel macOS support** -- And more that I forgot! diff --git a/UiDocs/Common/Buttons.xml b/UiDocs/Common/Buttons.xml new file mode 100644 index 0000000..029db4a --- /dev/null +++ b/UiDocs/Common/Buttons.xml @@ -0,0 +1,49 @@ + + + + + + diff --git a/UiDocs/Common/Slider.xml b/UiDocs/Common/Slider.xml new file mode 100644 index 0000000..87b8463 --- /dev/null +++ b/UiDocs/Common/Slider.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/UiDocs/Common/TextInput.xml b/UiDocs/Common/TextInput.xml new file mode 100644 index 0000000..5fba66a --- /dev/null +++ b/UiDocs/Common/TextInput.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/UiDocs/Common/TitleImage.xml b/UiDocs/Common/TitleImage.xml new file mode 100644 index 0000000..4d3500d --- /dev/null +++ b/UiDocs/Common/TitleImage.xml @@ -0,0 +1,5 @@ + + + diff --git a/UiDocs/Credits.xml b/UiDocs/Credits.xml new file mode 100644 index 0000000..950fda2 --- /dev/null +++ b/UiDocs/Credits.xml @@ -0,0 +1,160 @@ + + + + Select + Back + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UiDocs/Home.xml b/UiDocs/Home.xml new file mode 100644 index 0000000..f9824ab --- /dev/null +++ b/UiDocs/Home.xml @@ -0,0 +1,36 @@ + + + + + + Select + + + + + + + + + + + + + + + + + + + + diff --git a/UiDocs/Settings.xml b/UiDocs/Settings.xml new file mode 100644 index 0000000..9060d2b --- /dev/null +++ b/UiDocs/Settings.xml @@ -0,0 +1,218 @@ + + + + + + + Select + Back + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UiDocs/Versions.xml b/UiDocs/Versions.xml new file mode 100644 index 0000000..54b0195 --- /dev/null +++ b/UiDocs/Versions.xml @@ -0,0 +1,142 @@ + + + + + + + Select + Back + Install + + + + + + + + + + + + + diff --git a/assets/screenshots/main-window.png b/assets/screenshots/main-window.png deleted file mode 100644 index 6234411..0000000 Binary files a/assets/screenshots/main-window.png and /dev/null differ diff --git a/bun.lock b/bun.lock deleted file mode 100644 index dd3a7bb..0000000 --- a/bun.lock +++ /dev/null @@ -1,546 +0,0 @@ -{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "emerald-legacy-launcher", - "dependencies": { - "@tailwindcss/vite": "^4.2.1", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-opener": "^2.5.3", - "framer-motion": "^12.36.0", - "path": "^0.12.7", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router-dom": "^7.13.1", - "tauri-plugin-drpc": "^1.0.3", - "tauri-plugin-gamepad-api": "^0.0.5", - "three": "^0.183.2", - }, - "devDependencies": { - "@tauri-apps/cli": "^2.10.1", - "@types/react": "^19.1.8", - "@types/react-dom": "^19.1.6", - "@types/three": "^0.183.1", - "@vitejs/plugin-react": "^4.6.0", - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^3.4.19", - "typescript": "~5.8.3", - "vite": "^7.0.4", - }, - }, - }, - "packages": { - "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - - "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], - - "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], - - "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], - - "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], - - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], - - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], - - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - - "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], - - "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], - - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], - - "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], - - "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], - - "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - - "@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.12.0", "", {}, "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], - - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], - - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], - - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], - - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], - - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], - - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], - - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], - - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], - - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], - - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], - - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], - - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], - - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], - - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], - - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], - - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], - - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], - - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], - - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], - - "@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="], - - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="], - - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="], - - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="], - - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="], - - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="], - - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="], - - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="], - - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="], - - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="], - - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="], - - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="], - - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="], - - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="], - - "@tailwindcss/vite": ["@tailwindcss/vite@4.2.1", "", { "dependencies": { "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "tailwindcss": "4.2.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w=="], - - "@tauri-apps/api": ["@tauri-apps/api@2.10.1", "", {}, "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw=="], - - "@tauri-apps/cli": ["@tauri-apps/cli@2.10.1", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.1", "@tauri-apps/cli-darwin-x64": "2.10.1", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", "@tauri-apps/cli-linux-arm64-musl": "2.10.1", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-musl": "2.10.1", "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", "@tauri-apps/cli-win32-x64-msvc": "2.10.1" }, "bin": { "tauri": "tauri.js" } }, "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g=="], - - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ=="], - - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw=="], - - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w=="], - - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA=="], - - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg=="], - - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.1", "", { "os": "linux", "cpu": "none" }, "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw=="], - - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw=="], - - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ=="], - - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg=="], - - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw=="], - - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg=="], - - "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="], - - "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], - - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - - "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], - - "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - - "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - - "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - - "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], - - "@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="], - - "@types/three": ["@types/three@0.183.1", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": ">=0.5.17", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~1.0.1" } }, "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw=="], - - "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], - - "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], - - "@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], - - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - - "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], - - "autoprefixer": ["autoprefixer@10.4.27", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA=="], - - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": "dist/cli.cjs" }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], - - "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": "cli.js" }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], - - "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001778", "", {}, "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg=="], - - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], - - "cssesc": ["cssesc@3.0.0", "", { "bin": "bin/cssesc" }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - - "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], - - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.313", "", {}, "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA=="], - - "enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="], - - "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": "bin/esbuild" }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - - "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], - - "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - - "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], - - "framer-motion": ["framer-motion@12.36.0", "", { "dependencies": { "motion-dom": "^12.36.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - - "inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="], - - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "jiti": ["jiti@1.21.7", "", { "bin": "bin/jiti.js" }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], - - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - - "jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="], - - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], - - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="], - - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="], - - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="], - - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="], - - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="], - - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="], - - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="], - - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="], - - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="], - - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], - - "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], - - "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - - "meshoptimizer": ["meshoptimizer@1.0.1", "", {}, "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "motion-dom": ["motion-dom@12.36.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA=="], - - "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - - "nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - - "node-releases": ["node-releases@2.0.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="], - - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], - - "path": ["path@0.12.7", "", { "dependencies": { "process": "^0.11.1", "util": "^0.10.3" } }, "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], - - "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - - "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - - "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], - - "postcss-js": ["postcss-js@4.1.0", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw=="], - - "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], - - "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], - - "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - - "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - - "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - - "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], - - "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], - - "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], - - "react-router": ["react-router@7.13.1", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA=="], - - "react-router-dom": ["react-router-dom@7.13.1", "", { "dependencies": { "react-router": "7.13.1" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw=="], - - "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], - - "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - - "semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], - - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - - "tailwindcss": ["tailwindcss@3.4.19", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="], - - "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - - "tauri-plugin-drpc": ["tauri-plugin-drpc@1.0.3", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-vl5dXhjKbl7+Nf9veW12usdmIUtZXwEf91SzxQPZlbRRJ/sjizbbQlnkUTtx6baJuGzz0KXXgP9xUhF39BdiXQ=="], - - "tauri-plugin-gamepad-api": ["tauri-plugin-gamepad-api@0.0.5", "", { "dependencies": { "@tauri-apps/api": "2.1.1", "tslib": "^2.1.0" } }, "sha512-WO0xwXmPr4PMe9HzljKUbTkGv7J6ur2Df/OuEPsxBeSA5QPffAJR3N32M4pM4yW72D9Vt19XplPnHHDVATVMSw=="], - - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], - - "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - - "three": ["three@0.183.2", "", {}, "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ=="], - - "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], - - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], - - "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], - - "util": ["util@0.10.4", "", { "dependencies": { "inherits": "2.0.3" } }, "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A=="], - - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - - "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], - - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - - "@tailwindcss/node/tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], - - "@tailwindcss/vite/tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], - - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "tauri-plugin-gamepad-api/@tauri-apps/api": ["@tauri-apps/api@2.1.1", "", {}, "sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A=="], - } -} diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 0000000..a9a4560 --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,29 @@ +function(emerald_apply_warnings target) + if(MSVC) + target_compile_options(${target} PRIVATE /W4 /permissive-) + if(EMERALD_WARNINGS_AS_ERRORS) + target_compile_options(${target} PRIVATE /WX) + endif() + return() + endif() + + target_compile_options(${target} PRIVATE + -Wall + -Wextra + -Wpedantic + -Wshadow + -Wconversion + -Wsign-conversion + -Wnon-virtual-dtor + -Wold-style-cast + -Wcast-align + -Wunused + -Woverloaded-virtual + -Wnull-dereference + -Wdouble-promotion + -Wformat=2 + ) + if(EMERALD_WARNINGS_AS_ERRORS) + target_compile_options(${target} PRIVATE -Werror) + endif() +endfunction() diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake new file mode 100644 index 0000000..14ef475 --- /dev/null +++ b/cmake/Dependencies.cmake @@ -0,0 +1,135 @@ +include(FetchContent) +set(EMERALD_PC_MODULES CURL::libcurl Archive::libarchive) +if(EMERALD_USE_SYSTEM_DEPS) + find_package(CURL QUIET) + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND) + pkg_check_modules(EMERALD_ARCHIVE IMPORTED_TARGET libarchive) + endif() +elseif() + message(FATAL_ERROR "libcurl/libarchive system deps required") +endif() +function(emerald_find_sdl3) + if(EMERALD_USE_SYSTEM_DEPS) + find_package(SDL3 3.2 CONFIG QUIET) + if(SDL3_FOUND) + message(STATUS "Using system SDL3 ${SDL3_VERSION}") + return() + endif() + endif() + + FetchContent_Declare(SDL3 + GIT_REPOSITORY https://github.com/libsdl-org/SDL.git + GIT_TAG release-3.2.30 + GIT_SHALLOW TRUE + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(SDL3) + message(STATUS "SDL3 fetched from source") +endfunction() +function(emerald_find_sdl3_ttf) + if(EMERALD_USE_SYSTEM_DEPS) + find_package(SDL3_ttf CONFIG QUIET) + if(SDL3_ttf_FOUND) + message(STATUS "Using system SDL3_ttf ${SDL3_ttf_VERSION}") + return() + endif() + endif() + + FetchContent_Declare(SDL3_ttf + GIT_REPOSITORY https://github.com/libsdl-org/SDL_ttf.git + GIT_TAG release-3.2.2 + GIT_SHALLOW TRUE + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(SDL3_ttf) + message(STATUS "SDL3_ttf fetched from source") +endfunction() + +function(emerald_find_pugixml) + if(EMERALD_USE_SYSTEM_DEPS) + find_package(pugixml CONFIG QUIET) + if(pugixml_FOUND) + message(STATUS "Using system pugixml ${pugixml_VERSION}") + return() + endif() + endif() + FetchContent_Declare(pugixml + GIT_REPOSITORY https://github.com/zeux/pugixml.git + GIT_TAG v1.15 + GIT_SHALLOW TRUE + EXCLUDE_FROM_ALL + ) + set(BUILD_TESTS OFF CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(pugixml) + message(STATUS "pugixml fetched from source") +endfunction() +function(emerald_find_stb) + if(EMERALD_USE_SYSTEM_DEPS AND EXISTS "${EMERALD_SYSTEM_STB_DIR}/stb_image.h") + message(STATUS "Using system stb headers") + return() + endif() + + FetchContent_Declare(stb + GIT_REPOSITORY https://github.com/nothings/stb.git + GIT_TAG master + GIT_SHALLOW TRUE + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(stb) + message(STATUS "stb fetched from source") +endfunction() +function(emerald_find_miniaudio) + if(EMERALD_USE_SYSTEM_DEPS) + find_path(EMERALD_MINIAUDIO_INCLUDE_DIR NAMES miniaudio.h) + if(EMERALD_MINIAUDIO_INCLUDE_DIR) + message(STATUS "Using system miniaudio (${EMERALD_MINIAUDIO_INCLUDE_DIR})") + return() + endif() + endif() + + FetchContent_Declare(miniaudio + GIT_REPOSITORY https://github.com/mackron/miniaudio.git + GIT_TAG 0.11.25 + GIT_SHALLOW TRUE + SOURCE_SUBDIR cmake/emerald-miniaudio-no-subdir + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(miniaudio) + set(EMERALD_MINIAUDIO_INCLUDE_DIR "${miniaudio_SOURCE_DIR}" CACHE PATH "miniaudio include directory" FORCE) + message(STATUS "miniaudio fetched from source") +endfunction() +function(emerald_find_json) + if(EMERALD_USE_SYSTEM_DEPS) + find_package(nlohmann_json 3.11 CONFIG QUIET) + if(nlohmann_json_FOUND) + message(STATUS "Using system nlohmann_json") + return() + endif() + endif() + + FetchContent_Declare(nlohmann_json + URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + EXCLUDE_FROM_ALL + ) + FetchContent_MakeAvailable(nlohmann_json) + message(STATUS "nlohmann_json fetched from source") +endfunction() +set(EMERALD_SYSTEM_STB_DIR "/usr/include/stb") +emerald_find_sdl3() +emerald_find_sdl3_ttf() +emerald_find_json() +emerald_find_pugixml() +emerald_find_stb() +emerald_find_miniaudio() +if(NOT WIN32) + find_package(SQLite3 REQUIRED) +endif() + +add_library(emerald_stb INTERFACE) +if(EXISTS "${EMERALD_SYSTEM_STB_DIR}/stb_image.h") + target_include_directories(emerald_stb SYSTEM INTERFACE "${EMERALD_SYSTEM_STB_DIR}") +else() + target_include_directories(emerald_stb SYSTEM INTERFACE "${stb_SOURCE_DIR}") +endif() diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 5b993c3..0000000 --- a/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1784120854, - "narHash": "sha256-KesHgItiZPgGX740axSiQLcIQ8D24MDqNpkKYWIek8k=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "753cc8a3a87467296ddd1fa93f0cc3e81120ee46", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 906bd3c..0000000 --- a/flake.nix +++ /dev/null @@ -1,107 +0,0 @@ -{ - description = "LCE Emerald Launcher — FOSS cross-platform launcher for Minecraft Legacy Console Edition"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - }; - - outputs = - { self, nixpkgs }: - let - inherit (nixpkgs) lib; - systems = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - forAllSystems = lib.genAttrs systems; - pkgsFor = - system: - import nixpkgs { - inherit system; - overlays = [ self.overlays.default ]; - }; - - # Bump these together when packaging a new upstream stable release. - stableVersion = "1.6.0"; - stableSrcHash = "sha256-VlqBCZa42MLmJ1nUNlH7PIcLp/X7mBLCS/hm/ISiHNA="; - in - { - overlays.default = final: _prev: { - emerald-legacy-launcher = final.callPackage ./nix/package.nix { - version = stableVersion; - src = final.fetchFromGitHub { - owner = "LCE-Hub"; - repo = "LCE-Emerald-Launcher"; - rev = "v${stableVersion}"; - hash = stableSrcHash; - }; - }; - - emerald-legacy-launcher-git = final.callPackage ./nix/package.nix { - version = "unstable-${self.shortRev or self.dirtyShortRev or "dirty"}"; - src = self; - }; - }; - - packages = forAllSystems ( - system: - let - pkgs = pkgsFor system; - in - { - default = pkgs.emerald-legacy-launcher; - emerald-legacy-launcher = pkgs.emerald-legacy-launcher; - emerald-legacy-launcher-git = pkgs.emerald-legacy-launcher-git; - } - ); - - apps = forAllSystems (system: { - default = { - type = "app"; - program = lib.getExe self.packages.${system}.default; - }; - emerald-legacy-launcher-git = { - type = "app"; - program = lib.getExe self.packages.${system}.emerald-legacy-launcher-git; - }; - }); - - checks = forAllSystems (system: { - package = self.packages.${system}.default; - package-git = self.packages.${system}.emerald-legacy-launcher-git; - }); - - devShells = forAllSystems ( - system: - let - pkgs = pkgsFor system; - in - { - default = pkgs.mkShell { - inputsFrom = [ pkgs.emerald-legacy-launcher-git ]; - packages = with pkgs; [ - cargo - rustc - rustfmt - clippy - cargo-tauri - nodejs - pnpm_10 - unzip - libarchive - python3 - pkg-config - ]; - shellHook = '' - echo "Emerald Legacy Launcher dev shell" - echo " pnpm install && pnpm tauri dev" - ''; - }; - } - ); - - formatter = forAllSystems (system: (pkgsFor system).nixfmt); - }; -} diff --git a/flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml b/flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml index 49353e8..e2b4951 100644 --- a/flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml +++ b/flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml @@ -12,7 +12,7 @@ https://github.com Emerald Team - +

Latest stable release of the Emerald Legacy Launcher.

diff --git a/gentoo/games-util/emerald-legacy-launcher/Manifest b/gentoo/games-util/emerald-legacy-launcher/Manifest deleted file mode 100644 index b72ef44..0000000 --- a/gentoo/games-util/emerald-legacy-launcher/Manifest +++ /dev/null @@ -1 +0,0 @@ -DIST emerald-legacy-launcher-1.5.1.tar.gz 18500442 BLAKE2B 365d9dd36ee6fddb90625719b599c8fc492eba4ce0fb8926c953f2a7d7f4987bf77d91de6a140a489534ba61e8a71bf9e65d8e015a35af31bccb84ca3a023178 SHA512 c713ef81e56d55d7135fa4228f875822a3eee38ace86d8d28a59a8b4afeff28844bf698e9902eb66075b425a0fb71ae72969ae1fe99ce185a005b5f42a4dccc8 diff --git a/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-1.5.1.ebuild b/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-1.5.1.ebuild deleted file mode 100644 index 96fce97..0000000 --- a/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-1.5.1.ebuild +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2026 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit desktop xdg - -DESCRIPTION="FOSS cross-platform launcher for Minecraft Legacy Console Edition" -HOMEPAGE="https://github.com/LCE-Hub/LCE-Emerald-Launcher" -SRC_URI="https://github.com/LCE-Hub/LCE-Emerald-Launcher/archive/refs/tags/v${PV}.tar.gz -> ${P}.tar.gz" -S="${WORKDIR}/LCE-Emerald-Launcher-${PV}" - -LICENSE="GPL-3" -SLOT="0" -KEYWORDS="~amd64" - -# Cargo crates and npm packages are fetched at build time. -RESTRICT="network-sandbox" - -RDEPEND=" - dev-libs/glib:2 - dev-libs/libayatana-appindicator - dev-libs/openssl:= - net-libs/libsoup:3.0 - net-libs/webkit-gtk:4.1 - x11-libs/cairo - x11-libs/gdk-pixbuf:2 - x11-libs/gtk+:3 - x11-libs/pango -" -DEPEND="${RDEPEND}" -BDEPEND=" - || ( - >=dev-lang/rust-1.77.0:* - >=dev-lang/rust-bin-1.77.0:* - ) - net-libs/nodejs[npm] - virtual/pkgconfig -" - -# Rust binaries ignore *FLAGS from make.conf. -QA_FLAGS_IGNORED="usr/bin/emerald-legacy-launcher" - -src_prepare() { - default - - # Disable updater artifact signing (no Tauri signing key in distro builds). - sed -i \ - -e 's/"createUpdaterArtifacts": true/"createUpdaterArtifacts": false/' \ - src-tauri/tauri.conf.json || die -} - -src_compile() { - local -x CI=true - local -x npm_config_audit=false - local -x npm_config_fund=false - local -x npm_config_update_notifier=false - - npm install || die "npm install failed" - npm run tauri -- build --no-bundle || die "tauri build failed" -} - -src_install() { - dobin src-tauri/target/release/emerald-legacy-launcher - - newicon -s 32 src-tauri/icons/32x32.png emerald-legacy-launcher.png - newicon -s 64 src-tauri/icons/64x64.png emerald-legacy-launcher.png - newicon -s 128 src-tauri/icons/128x128.png emerald-legacy-launcher.png - newicon -s 256 src-tauri/icons/128x128@2x.png emerald-legacy-launcher.png - newicon -s 512 src-tauri/icons/icon.png emerald-legacy-launcher.png - - domenu "${FILESDIR}"/emerald-legacy-launcher.desktop - - insinto /usr/share/metainfo - newins flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml \ - io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml - - dodoc README.md LICENSE -} diff --git a/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-9999.ebuild b/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-9999.ebuild deleted file mode 100644 index 318574c..0000000 --- a/gentoo/games-util/emerald-legacy-launcher/emerald-legacy-launcher-9999.ebuild +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2026 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit desktop git-r3 xdg - -DESCRIPTION="FOSS cross-platform launcher for Minecraft Legacy Console Edition" -HOMEPAGE="https://github.com/LCE-Hub/LCE-Emerald-Launcher" -EGIT_REPO_URI="https://github.com/LCE-Hub/LCE-Emerald-Launcher.git" - -LICENSE="GPL-3" -SLOT="0" -PROPERTIES="live" - -# Cargo crates and npm packages are fetched at build time. -RESTRICT="network-sandbox" - -RDEPEND=" - dev-libs/glib:2 - dev-libs/libayatana-appindicator - dev-libs/openssl:= - net-libs/libsoup:3.0 - net-libs/webkit-gtk:4.1 - x11-libs/cairo - x11-libs/gdk-pixbuf:2 - x11-libs/gtk+:3 - x11-libs/pango -" -DEPEND="${RDEPEND}" -BDEPEND=" - || ( - >=dev-lang/rust-1.77.0:* - >=dev-lang/rust-bin-1.77.0:* - ) - net-libs/nodejs[npm] - virtual/pkgconfig -" - -# Rust binaries ignore *FLAGS from make.conf. -QA_FLAGS_IGNORED="usr/bin/emerald-legacy-launcher" - -src_prepare() { - default - - # Prefer npm for the frontend build; disable updater artifact signing - # (no Tauri signing key in distro builds). - sed -i \ - -e 's/"createUpdaterArtifacts": true/"createUpdaterArtifacts": false/' \ - src-tauri/tauri.conf.json || die -} - -src_compile() { - local -x CI=true - local -x npm_config_audit=false - local -x npm_config_fund=false - local -x npm_config_update_notifier=false - - npm install || die "npm install failed" - npm run tauri -- build --no-bundle || die "tauri build failed" -} - -src_install() { - dobin src-tauri/target/release/emerald-legacy-launcher - - newicon -s 32 src-tauri/icons/32x32.png emerald-legacy-launcher.png - newicon -s 64 src-tauri/icons/64x64.png emerald-legacy-launcher.png - newicon -s 128 src-tauri/icons/128x128.png emerald-legacy-launcher.png - newicon -s 256 src-tauri/icons/128x128@2x.png emerald-legacy-launcher.png - newicon -s 512 src-tauri/icons/icon.png emerald-legacy-launcher.png - - domenu "${FILESDIR}"/emerald-legacy-launcher.desktop - - insinto /usr/share/metainfo - newins flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml \ - io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.metainfo.xml - - dodoc README.md LICENSE -} diff --git a/gentoo/games-util/emerald-legacy-launcher/files/emerald-legacy-launcher.desktop b/gentoo/games-util/emerald-legacy-launcher/files/emerald-legacy-launcher.desktop deleted file mode 100644 index 58919c1..0000000 --- a/gentoo/games-util/emerald-legacy-launcher/files/emerald-legacy-launcher.desktop +++ /dev/null @@ -1,11 +0,0 @@ -[Desktop Entry] -Name=LCE Emerald Launcher -Comment=FOSS cross-platform launcher for Minecraft Legacy Console Edition -Exec=emerald-legacy-launcher %u -Icon=emerald-legacy-launcher -Type=Application -Categories=Game; -MimeType=x-scheme-handler/emerald;x-scheme-handler/emeraldlauncher;x-scheme-handler/discord-1482504445152460871; -StartupNotify=true -StartupWMClass=emerald-legacy-launcher -Terminal=false diff --git a/gentoo/games-util/emerald-legacy-launcher/metadata.xml b/gentoo/games-util/emerald-legacy-launcher/metadata.xml deleted file mode 100644 index 0164f8d..0000000 --- a/gentoo/games-util/emerald-legacy-launcher/metadata.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - LCE-Hub/LCE-Emerald-Launcher - https://github.com/LCE-Hub/LCE-Emerald-Launcher/issues - - - LCE Emerald Launcher is a FOSS cross-platform Tauri launcher for - Minecraft Legacy Console Edition. It installs community builds, - manages versions, skins, and workshop content, and launches the game - via Wine/Proton on Linux. - - diff --git a/gentoo/metadata/layout.conf b/gentoo/metadata/layout.conf deleted file mode 100644 index 20fcfea..0000000 --- a/gentoo/metadata/layout.conf +++ /dev/null @@ -1,3 +0,0 @@ -masters = gentoo -thin-manifests = true -sign-manifests = false diff --git a/gentoo/profiles/repo_name b/gentoo/profiles/repo_name deleted file mode 100644 index 4973375..0000000 --- a/gentoo/profiles/repo_name +++ /dev/null @@ -1 +0,0 @@ -emerald-legacy-launcher diff --git a/index.html b/index.html deleted file mode 100644 index 0405fef..0000000 --- a/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - Emerald Legacy Launcher - - - -
- - - diff --git a/nix/package.nix b/nix/package.nix deleted file mode 100644 index f42e79f..0000000 --- a/nix/package.nix +++ /dev/null @@ -1,135 +0,0 @@ -{ - lib, - stdenv, - rustPlatform, - cargo-tauri, - nodejs, - pkg-config, - pnpm_10, - fetchPnpmDeps, - pnpmConfigHook, - wrapGAppsHook4, - openssl, - webkitgtk_4_1, - glib-networking, - libayatana-appindicator, - librsvg, - udev, - version ? "1.5.1", - src ? null, -}: - -# Disable updater artifact signing — Nix builds have no Tauri signing key. -let - tauriConfOverride = builtins.toFile "tauri-nix.conf.json" '' - { - "bundle": { - "createUpdaterArtifacts": false - } - } - ''; - - defaultSrc = lib.cleanSourceWith { - src = ../.; - filter = - path: _type: - let - baseName = baseNameOf path; - in - !(builtins.elem baseName [ - ".git" - "node_modules" - "target" - "dist" - "build-flatpak" - "emerald-repo" - "result" - "result-dev" - ]); - }; -in -rustPlatform.buildRustPackage (finalAttrs: { - pname = "emerald-legacy-launcher"; - inherit version; - - src = if src != null then src else defaultSrc; - - cargoRoot = "src-tauri"; - buildAndTestSubdir = finalAttrs.cargoRoot; - - cargoHash = "sha256-tSbFyle2eQ5Dw9fTXloIepOZU1UxhkF6/KZBRXehm4w="; - - pnpmDeps = fetchPnpmDeps { - inherit (finalAttrs) pname version src; - pnpm = pnpm_10; - fetcherVersion = 3; - hash = "sha256-6na8YlSTkdnSse8DQjBnTBpfmKSYj3+1FLWVyyfUx1g="; - }; - - nativeBuildInputs = [ - cargo-tauri.hook - nodejs - pkg-config - pnpmConfigHook - pnpm_10 - ] - ++ lib.optionals stdenv.hostPlatform.isLinux [ wrapGAppsHook4 ]; - - buildInputs = [ - openssl - ] - ++ lib.optionals stdenv.hostPlatform.isLinux [ - glib-networking - libayatana-appindicator - librsvg - udev - webkitgtk_4_1 - ]; - - tauriBuildFlags = [ - "-c" - tauriConfOverride - ]; - - postPatch = lib.optionalString stdenv.hostPlatform.isLinux '' - substituteInPlace "$cargoDepsCopy"/*/libappindicator-sys-*/src/lib.rs \ - --replace-fail "libayatana-appindicator3.so.1" \ - "${libayatana-appindicator}/lib/libayatana-appindicator3.so.1" - ''; - - # Prefer the project's pnpm frontend build over the npm beforeBuildCommand. - preBuild = '' - substituteInPlace src-tauri/tauri.conf.json \ - --replace-fail '"beforeBuildCommand": "npm run build"' \ - '"beforeBuildCommand": "pnpm run build"' - ''; - - preFixup = lib.optionalString stdenv.hostPlatform.isLinux '' - gappsWrapperArgs+=( - --prefix LD_LIBRARY_PATH : ${ - lib.makeLibraryPath [ - libayatana-appindicator - udev - ] - } - ) - ''; - - doCheck = false; - - env = { - CI = "true"; - }; - - meta = { - description = "FOSS cross-platform launcher for Minecraft Legacy Console Edition"; - homepage = "https://github.com/LCE-Hub/LCE-Emerald-Launcher"; - changelog = lib.mkIf (!(lib.hasPrefix "unstable-" version)) ( - "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/tag/v${version}" - ); - license = lib.licenses.gpl3Only; - mainProgram = "emerald-legacy-launcher"; - platforms = lib.platforms.linux ++ lib.platforms.darwin; - maintainers = [ ]; - }; -}) diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 75595a4..0000000 --- a/package-lock.json +++ /dev/null @@ -1,4741 +0,0 @@ -{ - "name": "emerald-legacy-launcher", - "version": "1.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "emerald-legacy-launcher", - "version": "1.1.0", - "dependencies": { - "@tauri-apps/api": "^2", - "@tauri-apps/plugin-opener": "^2", - "@tauri-apps/plugin-process": "~2.3.1", - "@tauri-apps/plugin-updater": "~2.10.1", - "framer-motion": "^12.36.0", - "pako": "^2.1.0", - "qrcode": "^1.5.4", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-markdown": "^10.1.0", - "remark-gfm": "^4.0.1", - "three": "^0.183.2" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.2.1", - "@tailwindcss/vite": "^4.2.1", - "@tauri-apps/cli": "^2", - "@types/pako": "^2.0.4", - "@types/qrcode": "^1.5.6", - "@types/react": "^19.1.8", - "@types/react-dom": "^19.1.6", - "@types/three": "^0.183.1", - "@vitejs/plugin-react": "^4.6.0", - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.1", - "tauri-plugin-drpc": "^1.0.3", - "tauri-plugin-gamepad-api": "^0.0.5", - "typescript": "~5.8.3", - "vite": "^7.0.4" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@dimforge/rapier3d-compat": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", - "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.1.tgz", - "integrity": "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "postcss": "^8.5.6", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", - "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "tailwindcss": "4.2.1" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" - } - }, - "node_modules/@tauri-apps/api": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", - "integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", - "license": "Apache-2.0 OR MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - } - }, - "node_modules/@tauri-apps/cli": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz", - "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "bin": { - "tauri": "tauri.js" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.10.1", - "@tauri-apps/cli-darwin-x64": "2.10.1", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", - "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", - "@tauri-apps/cli-linux-arm64-musl": "2.10.1", - "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", - "@tauri-apps/cli-linux-x64-gnu": "2.10.1", - "@tauri-apps/cli-linux-x64-musl": "2.10.1", - "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", - "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", - "@tauri-apps/cli-win32-x64-msvc": "2.10.1" - } - }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz", - "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz", - "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz", - "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz", - "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz", - "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz", - "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz", - "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz", - "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz", - "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz", - "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz", - "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/plugin-opener": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.3.tgz", - "integrity": "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.8.0" - } - }, - "node_modules/@tauri-apps/plugin-process": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-process/-/plugin-process-2.3.1.tgz", - "integrity": "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.8.0" - } - }, - "node_modules/@tauri-apps/plugin-updater": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-updater/-/plugin-updater-2.10.1.tgz", - "integrity": "sha512-NFYMg+tWOZPJdzE/PpFj2qfqwAWwNS3kXrb1tm1gnBJ9mYzZ4WDRrwy8udzWoAnfGCHLuePNLY1WVCNHnh3eRA==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.10.1" - } - }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.8.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", - "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, - "node_modules/@types/pako": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", - "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/qrcode": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz", - "integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/three": { - "version": "0.183.1", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", - "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@dimforge/rapier3d-compat": "~0.12.0", - "@tweenjs/tween.js": "~23.1.3", - "@types/stats.js": "*", - "@types/webxr": ">=0.5.17", - "@webgpu/types": "*", - "fflate": "~0.8.2", - "meshoptimizer": "~1.0.1" - } - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", - "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/@webgpu/types": { - "version": "0.1.69", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", - "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.8", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz", - "integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001778", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001778.tgz", - "integrity": "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.313", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz", - "integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/framer-motion": { - "version": "12.36.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.36.0.tgz", - "integrity": "sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw==", - "license": "MIT", - "dependencies": { - "motion-dom": "^12.36.0", - "motion-utils": "^12.36.0", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", - "license": "MIT" - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/meshoptimizer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", - "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "license": "MIT", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/motion-dom": { - "version": "12.36.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.36.0.tgz", - "integrity": "sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA==", - "license": "MIT", - "dependencies": { - "motion-utils": "^12.36.0" - } - }, - "node_modules/motion-utils": { - "version": "12.36.0", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", - "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pako": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", - "license": "(MIT AND Zlib)" - }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/qrcode": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", - "license": "MIT", - "dependencies": { - "dijkstrajs": "^1.0.1", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.4" - } - }, - "node_modules/react-markdown": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remark-gfm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC" - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/style-to-js": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", - "license": "MIT", - "dependencies": { - "style-to-object": "1.0.14" - } - }, - "node_modules/style-to-object": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", - "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.7" - } - }, - "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tauri-plugin-drpc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tauri-plugin-drpc/-/tauri-plugin-drpc-1.0.3.tgz", - "integrity": "sha512-vl5dXhjKbl7+Nf9veW12usdmIUtZXwEf91SzxQPZlbRRJ/sjizbbQlnkUTtx6baJuGzz0KXXgP9xUhF39BdiXQ==", - "dev": true, - "peerDependencies": { - "typescript": "^5.0.0" - } - }, - "node_modules/tauri-plugin-gamepad-api": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/tauri-plugin-gamepad-api/-/tauri-plugin-gamepad-api-0.0.5.tgz", - "integrity": "sha512-WO0xwXmPr4PMe9HzljKUbTkGv7J6ur2Df/OuEPsxBeSA5QPffAJR3N32M4pM4yW72D9Vt19XplPnHHDVATVMSw==", - "dev": true, - "dependencies": { - "@tauri-apps/api": "2.1.1", - "tslib": "^2.1.0" - } - }, - "node_modules/tauri-plugin-gamepad-api/node_modules/@tauri-apps/api": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.1.1.tgz", - "integrity": "sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - } - }, - "node_modules/three": { - "version": "0.183.2", - "resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz", - "integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "dev": true, - "license": "MIT" - }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index e5da8b8..0000000 --- a/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "emerald-legacy-launcher", - "private": true, - "version": "1.6.1", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "tauri": "tauri", - "tauri:build": "tauri build && pnpm run post-build:macos", - "post-build:macos": "bash src-tauri/scripts/post-build-macos.sh", - "android:assets": "node scripts/download-android-assets.mjs", - "flatpak": "flatpak-builder --user --install-deps-from=flathub --repo=emerald-repo --force-clean build-flatpak flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.yml && flatpak build-bundle emerald-repo emerald.flatpak io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher", - "goldmapper": "node scripts/build-goldmapper.mjs" - }, - "dependencies": { - "@tauri-apps/api": "^2", - "@tauri-apps/plugin-deep-link": "~2.4.9", - "@tauri-apps/plugin-opener": "^2", - "@tauri-apps/plugin-process": "~2.3.1", - "@tauri-apps/plugin-updater": "~2.10.1", - "framer-motion": "^12.36.0", - "i18next": "^26.4.0", - "i18next-browser-languagedetector": "^8.2.1", - "pako": "^2.1.0", - "qrcode": "^1.5.4", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-i18next": "^17.0.12", - "react-markdown": "^10.1.0", - "rehype-raw": "^7.0.0", - "rehype-sanitize": "^6.0.0", - "remark-gfm": "^4.0.1", - "three": "^0.183.2" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.2.1", - "@tailwindcss/vite": "^4.2.1", - "@tauri-apps/cli": "^2", - "@types/pako": "^2.0.4", - "@types/qrcode": "^1.5.6", - "@types/react": "^19.1.8", - "@types/react-dom": "^19.1.6", - "@types/three": "^0.183.1", - "@vitejs/plugin-react": "^4.6.0", - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.1", - "tauri-plugin-drpc": "^1.0.3", - "tauri-plugin-gamepad-api": "^0.0.5", - "typescript": "~5.8.3", - "vite": "^7.0.4" - } -} diff --git a/pkg/AppImage/AppImage.sh b/pkg/AppImage/AppImage.sh deleted file mode 100755 index 844c7f0..0000000 --- a/pkg/AppImage/AppImage.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -#neo: credits: https://github.com/cjonas1999/OverBind/blob/master/pkg/AppImage/AppImage.sh -set -eu -ARCH="$(uname -m)" -SHARUN_REPO="https://raw.githubusercontent.com/pkgforge-dev/Anylinux-AppImages" -_commits_json=$(mktemp) -wget -qO "$_commits_json" \ - "https://api.github.com/repos/pkgforge-dev/Anylinux-AppImages/commits?path=useful-tools/&per_page=100" - -STABLE_SHA=$(node -e " -const data = JSON.parse(require('fs').readFileSync('$_commits_json', 'utf8')); -const now = Date.now(), h24 = 864e5; -for (let i = 0; i < data.length; i++) { - const t = new Date(data[i].commit.committer.date).getTime(); - if (now - t < h24) continue; - const prev = data[i - 1]; - if (!prev || new Date(prev.commit.committer.date).getTime() - t >= h24) { - process.stdout.write(data[i].sha); - process.exit(0); - } -} -process.stderr.write('No settled commit found in last 100 commits\n'); -process.exit(1); -") -rm -f "$_commits_json" -echo "Pinning sharun scripts to settled commit $STABLE_SHA" -SHARUN="$SHARUN_REPO/$STABLE_SHA/useful-tools/quick-sharun.sh" -DEBLOATED_PKGS="$SHARUN_REPO/$STABLE_SHA/useful-tools/get-debloated-pkgs.sh" -#export UPINFO="gh-releases-zsync|${GITHUB_REPOSITORY%/*}|${GITHUB_REPOSITORY#*/}|latest|*$ARCH.AppImage.zsync" -export OUTNAME=Emerald-Legacy-Launcher-anylinux-"$ARCH".AppImage -export DESKTOP="/usr/share/applications/LCE Emerald Launcher.desktop" -export ICON=/usr/share/icons/hicolor/256x256@2/apps/emerald-legacy-launcher.png -export DEPLOY_OPENGL=1 -rm -rf AppDir dist appinfo -wget --retry-connrefused --tries=30 "$DEBLOATED_PKGS" -O ./get-debloated-pkgs -wget --retry-connrefused --tries=30 "$SHARUN" -O ./quick-sharun -chmod +x ./quick-sharun ./get-debloated-pkgs -./get-debloated-pkgs --add-common --prefer-nano -./quick-sharun \ - /usr/bin/emerald-legacy-launcher \ - /usr/lib/libayatana-appindicator*.so* - -mkdir -p "AppDir/usr/lib" -cp -r "/usr/lib/LCE Emerald Launcher" "AppDir/usr/lib/" -./quick-sharun --make-appimage -mkdir -p ./dist -mv -v ./*.AppImage* ./dist -echo "All Done!" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index fe09479..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,3136 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@tauri-apps/api': - specifier: ^2 - version: 2.10.1 - '@tauri-apps/plugin-deep-link': - specifier: ~2.4.9 - version: 2.4.9 - '@tauri-apps/plugin-opener': - specifier: ^2 - version: 2.5.3 - '@tauri-apps/plugin-process': - specifier: ~2.3.1 - version: 2.3.1 - '@tauri-apps/plugin-updater': - specifier: ~2.10.1 - version: 2.10.1 - framer-motion: - specifier: ^12.36.0 - version: 12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - i18next: - specifier: ^26.4.0 - version: 26.4.0(typescript@5.8.3) - i18next-browser-languagedetector: - specifier: ^8.2.1 - version: 8.2.1 - pako: - specifier: ^2.1.0 - version: 2.1.0 - qrcode: - specifier: ^1.5.4 - version: 1.5.4 - react: - specifier: ^19.1.0 - version: 19.2.4 - react-dom: - specifier: ^19.1.0 - version: 19.2.4(react@19.2.4) - react-i18next: - specifier: ^17.0.12 - version: 17.0.12(i18next@26.4.0(typescript@5.8.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.8.3) - react-markdown: - specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.14)(react@19.2.4) - rehype-raw: - specifier: ^7.0.0 - version: 7.0.0 - rehype-sanitize: - specifier: ^6.0.0 - version: 6.0.0 - remark-gfm: - specifier: ^4.0.1 - version: 4.0.1 - three: - specifier: ^0.183.2 - version: 0.183.2 - devDependencies: - '@tailwindcss/postcss': - specifier: ^4.2.1 - version: 4.2.1 - '@tailwindcss/vite': - specifier: ^4.2.1 - version: 4.2.1(vite@7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1)) - '@tauri-apps/cli': - specifier: ^2 - version: 2.10.1 - '@types/pako': - specifier: ^2.0.4 - version: 2.0.4 - '@types/qrcode': - specifier: ^1.5.6 - version: 1.5.6 - '@types/react': - specifier: ^19.1.8 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.1.6 - version: 19.2.3(@types/react@19.2.14) - '@types/three': - specifier: ^0.183.1 - version: 0.183.1 - '@vitejs/plugin-react': - specifier: ^4.6.0 - version: 4.7.0(vite@7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1)) - autoprefixer: - specifier: ^10.4.27 - version: 10.4.27(postcss@8.5.8) - postcss: - specifier: ^8.5.8 - version: 8.5.8 - tailwindcss: - specifier: ^4.2.1 - version: 4.2.1 - tauri-plugin-drpc: - specifier: ^1.0.3 - version: 1.0.3(typescript@5.8.3) - tauri-plugin-gamepad-api: - specifier: ^0.0.5 - version: 0.0.5 - typescript: - specifier: ~5.8.3 - version: 5.8.3 - vite: - specifier: ^7.0.4 - version: 7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1) - -packages: - - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.29.7': - resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@dimforge/rapier3d-compat@0.12.0': - resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==} - - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} - cpu: [x64] - os: [win32] - - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} - - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} - engines: {node: '>= 20'} - - '@tailwindcss/postcss@4.2.1': - resolution: {integrity: sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==} - - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 - - '@tauri-apps/api@2.1.1': - resolution: {integrity: sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==} - - '@tauri-apps/api@2.10.1': - resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} - - '@tauri-apps/api@2.11.0': - resolution: {integrity: sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==} - - '@tauri-apps/cli-darwin-arm64@2.10.1': - resolution: {integrity: sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tauri-apps/cli-darwin-x64@2.10.1': - resolution: {integrity: sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.1': - resolution: {integrity: sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tauri-apps/cli-linux-arm64-gnu@2.10.1': - resolution: {integrity: sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tauri-apps/cli-linux-arm64-musl@2.10.1': - resolution: {integrity: sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tauri-apps/cli-linux-riscv64-gnu@2.10.1': - resolution: {integrity: sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==} - engines: {node: '>= 10'} - cpu: [riscv64] - os: [linux] - - '@tauri-apps/cli-linux-x64-gnu@2.10.1': - resolution: {integrity: sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tauri-apps/cli-linux-x64-musl@2.10.1': - resolution: {integrity: sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tauri-apps/cli-win32-arm64-msvc@2.10.1': - resolution: {integrity: sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tauri-apps/cli-win32-ia32-msvc@2.10.1': - resolution: {integrity: sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@tauri-apps/cli-win32-x64-msvc@2.10.1': - resolution: {integrity: sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tauri-apps/cli@2.10.1': - resolution: {integrity: sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==} - engines: {node: '>= 10'} - hasBin: true - - '@tauri-apps/plugin-deep-link@2.4.9': - resolution: {integrity: sha512-u0SKOUHnJ1wqeqXsDFq2+kASCBj9xxbG0g9XZWPy9SOmU4wXtp6b/wiYpm6oH6/5fBTQsLqnLhIvqLBRpgHJlA==} - - '@tauri-apps/plugin-opener@2.5.3': - resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==} - - '@tauri-apps/plugin-process@2.3.1': - resolution: {integrity: sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==} - - '@tauri-apps/plugin-updater@2.10.1': - resolution: {integrity: sha512-NFYMg+tWOZPJdzE/PpFj2qfqwAWwNS3kXrb1tm1gnBJ9mYzZ4WDRrwy8udzWoAnfGCHLuePNLY1WVCNHnh3eRA==} - - '@tweenjs/tween.js@23.1.3': - resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/debug@4.1.13': - resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} - - '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@25.8.0': - resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} - - '@types/pako@2.0.4': - resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} - - '@types/qrcode@1.5.6': - resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - - '@types/stats.js@0.17.4': - resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} - - '@types/three@0.183.1': - resolution: {integrity: sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==} - - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/webxr@0.5.24': - resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@webgpu/types@0.1.69': - resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - autoprefixer@10.4.27: - resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - bail@2.0.2: - resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - - baseline-browser-mapping@2.10.8: - resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001780: - resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - - character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decode-named-character-reference@1.3.0: - resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - - electron-to-chromium@1.5.313: - resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - enhanced-resolve@5.20.1: - resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} - engines: {node: '>=10.13.0'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - estree-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - - framer-motion@12.38.0: - resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - hast-util-from-parse5@8.0.3: - resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hast-util-raw@9.1.0: - resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - - hast-util-sanitize@5.0.2: - resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==} - - hast-util-to-jsx-runtime@2.3.6: - resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} - - hast-util-to-parse5@8.0.1: - resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hastscript@9.0.1: - resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - - html-parse-stringify@4.0.1: - resolution: {integrity: sha512-0zHsZJrK7S3K2aucXWL6ycoYJ/iNtIcFHC/nYQgFklPtrv5LpJctIiSCroWZWeuoXvuyFdzp6KzjJQ+OT5MfFw==} - - html-url-attributes@3.0.1: - resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - i18next-browser-languagedetector@8.2.1: - resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} - - i18next@26.4.0: - resolution: {integrity: sha512-rsmK5bFqsD1AetSFSIa43wtNR4WpvvH4p0tLEsTxkC7QTrfdFm06nbQ95bh8Og4wwaCnUEcm9DVYL2cgxitiQg==} - peerDependencies: - typescript: ^5 || ^6 || ^7 - peerDependenciesMeta: - typescript: - optional: true - - inline-style-parser@0.2.7: - resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} - - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} - engines: {node: '>= 12.0.0'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - markdown-table@3.0.4: - resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - - mdast-util-find-and-replace@3.0.2: - resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - - mdast-util-from-markdown@2.0.3: - resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} - - mdast-util-gfm-autolink-literal@2.0.1: - resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} - - mdast-util-gfm-footnote@2.1.0: - resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} - - mdast-util-gfm-strikethrough@2.0.0: - resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} - - mdast-util-gfm-table@2.0.0: - resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} - - mdast-util-gfm-task-list-item@2.0.0: - resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} - - mdast-util-gfm@3.1.0: - resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} - - mdast-util-mdx-expression@2.0.1: - resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} - - mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} - - mdast-util-mdxjs-esm@2.0.1: - resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} - - mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - - mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - - meshoptimizer@1.0.1: - resolution: {integrity: sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==} - - micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - - micromark-extension-gfm-autolink-literal@2.1.0: - resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} - - micromark-extension-gfm-footnote@2.1.0: - resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} - - micromark-extension-gfm-strikethrough@2.1.0: - resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} - - micromark-extension-gfm-table@2.1.1: - resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} - - micromark-extension-gfm-tagfilter@2.0.0: - resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} - - micromark-extension-gfm-task-list-item@2.1.0: - resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} - - micromark-extension-gfm@3.0.0: - resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} - - micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - - micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - - micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - - micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - - micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - - micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - - micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - - micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - - micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - - micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - - micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - - motion-dom@12.38.0: - resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==} - - motion-utils@12.36.0: - resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - pako@2.1.0: - resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} - - parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pngjs@5.0.0: - resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} - engines: {node: '>=10.13.0'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} - engines: {node: ^10 || ^12 || >=14} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - qrcode@1.5.4: - resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} - engines: {node: '>=10.13.0'} - hasBin: true - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - - react-i18next@17.0.12: - resolution: {integrity: sha512-lFWPEGkxQ6RhusdUkysFBD58VHfSSzvHBzqMgN0SvfVpdQGfwtNkStTqdy08/sJd7s807qqutgx93fRpD0DJ3Q==} - peerDependencies: - i18next: '>= 26.2.0' - react: '>= 16.8.0' - react-dom: '*' - react-native: '*' - typescript: ^5 || ^6 || ^7 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - - react-markdown@10.1.0: - resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} - peerDependencies: - '@types/react': '>=18' - react: '>=18' - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - - rehype-raw@7.0.0: - resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} - - rehype-sanitize@6.0.0: - resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==} - - remark-gfm@4.0.1: - resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} - - remark-parse@11.0.0: - resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - - remark-rehype@11.1.2: - resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} - - remark-stringify@11.0.0: - resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - style-to-js@1.1.21: - resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} - - style-to-object@1.0.14: - resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - - tauri-plugin-drpc@1.0.3: - resolution: {integrity: sha512-vl5dXhjKbl7+Nf9veW12usdmIUtZXwEf91SzxQPZlbRRJ/sjizbbQlnkUTtx6baJuGzz0KXXgP9xUhF39BdiXQ==} - peerDependencies: - typescript: ^5.0.0 - - tauri-plugin-gamepad-api@0.0.5: - resolution: {integrity: sha512-WO0xwXmPr4PMe9HzljKUbTkGv7J6ur2Df/OuEPsxBeSA5QPffAJR3N32M4pM4yW72D9Vt19XplPnHHDVATVMSw==} - - three@0.183.2: - resolution: {integrity: sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - trough@2.2.0: - resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@7.24.6: - resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - - unified@11.0.5: - resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - vfile-location@5.0.3: - resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@alloc/quick-lru@5.2.0': {} - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.2': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/runtime@7.29.7': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@dimforge/rapier3d-compat@0.12.0': {} - - '@esbuild/aix-ppc64@0.27.4': - optional: true - - '@esbuild/android-arm64@0.27.4': - optional: true - - '@esbuild/android-arm@0.27.4': - optional: true - - '@esbuild/android-x64@0.27.4': - optional: true - - '@esbuild/darwin-arm64@0.27.4': - optional: true - - '@esbuild/darwin-x64@0.27.4': - optional: true - - '@esbuild/freebsd-arm64@0.27.4': - optional: true - - '@esbuild/freebsd-x64@0.27.4': - optional: true - - '@esbuild/linux-arm64@0.27.4': - optional: true - - '@esbuild/linux-arm@0.27.4': - optional: true - - '@esbuild/linux-ia32@0.27.4': - optional: true - - '@esbuild/linux-loong64@0.27.4': - optional: true - - '@esbuild/linux-mips64el@0.27.4': - optional: true - - '@esbuild/linux-ppc64@0.27.4': - optional: true - - '@esbuild/linux-riscv64@0.27.4': - optional: true - - '@esbuild/linux-s390x@0.27.4': - optional: true - - '@esbuild/linux-x64@0.27.4': - optional: true - - '@esbuild/netbsd-arm64@0.27.4': - optional: true - - '@esbuild/netbsd-x64@0.27.4': - optional: true - - '@esbuild/openbsd-arm64@0.27.4': - optional: true - - '@esbuild/openbsd-x64@0.27.4': - optional: true - - '@esbuild/openharmony-arm64@0.27.4': - optional: true - - '@esbuild/sunos-x64@0.27.4': - optional: true - - '@esbuild/win32-arm64@0.27.4': - optional: true - - '@esbuild/win32-ia32@0.27.4': - optional: true - - '@esbuild/win32-x64@0.27.4': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.59.0': - optional: true - - '@rollup/rollup-android-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-x64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.59.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.59.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.59.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.59.0': - optional: true - - '@tailwindcss/node@4.2.1': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.1 - jiti: 2.6.1 - lightningcss: 1.31.1 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.2.1 - - '@tailwindcss/oxide-android-arm64@4.2.1': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.2.1': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.2.1': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.2.1': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - optional: true - - '@tailwindcss/oxide@4.2.1': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - - '@tailwindcss/postcss@4.2.1': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - postcss: 8.5.8 - tailwindcss: 4.2.1 - - '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1))': - dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1) - - '@tauri-apps/api@2.1.1': {} - - '@tauri-apps/api@2.10.1': {} - - '@tauri-apps/api@2.11.0': {} - - '@tauri-apps/cli-darwin-arm64@2.10.1': - optional: true - - '@tauri-apps/cli-darwin-x64@2.10.1': - optional: true - - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.1': - optional: true - - '@tauri-apps/cli-linux-arm64-gnu@2.10.1': - optional: true - - '@tauri-apps/cli-linux-arm64-musl@2.10.1': - optional: true - - '@tauri-apps/cli-linux-riscv64-gnu@2.10.1': - optional: true - - '@tauri-apps/cli-linux-x64-gnu@2.10.1': - optional: true - - '@tauri-apps/cli-linux-x64-musl@2.10.1': - optional: true - - '@tauri-apps/cli-win32-arm64-msvc@2.10.1': - optional: true - - '@tauri-apps/cli-win32-ia32-msvc@2.10.1': - optional: true - - '@tauri-apps/cli-win32-x64-msvc@2.10.1': - optional: true - - '@tauri-apps/cli@2.10.1': - optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.10.1 - '@tauri-apps/cli-darwin-x64': 2.10.1 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.10.1 - '@tauri-apps/cli-linux-arm64-gnu': 2.10.1 - '@tauri-apps/cli-linux-arm64-musl': 2.10.1 - '@tauri-apps/cli-linux-riscv64-gnu': 2.10.1 - '@tauri-apps/cli-linux-x64-gnu': 2.10.1 - '@tauri-apps/cli-linux-x64-musl': 2.10.1 - '@tauri-apps/cli-win32-arm64-msvc': 2.10.1 - '@tauri-apps/cli-win32-ia32-msvc': 2.10.1 - '@tauri-apps/cli-win32-x64-msvc': 2.10.1 - - '@tauri-apps/plugin-deep-link@2.4.9': - dependencies: - '@tauri-apps/api': 2.11.0 - - '@tauri-apps/plugin-opener@2.5.3': - dependencies: - '@tauri-apps/api': 2.10.1 - - '@tauri-apps/plugin-process@2.3.1': - dependencies: - '@tauri-apps/api': 2.10.1 - - '@tauri-apps/plugin-updater@2.10.1': - dependencies: - '@tauri-apps/api': 2.10.1 - - '@tweenjs/tween.js@23.1.3': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/debug@4.1.13': - dependencies: - '@types/ms': 2.1.0 - - '@types/estree-jsx@1.0.5': - dependencies: - '@types/estree': 1.0.8 - - '@types/estree@1.0.8': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/ms@2.1.0': {} - - '@types/node@25.8.0': - dependencies: - undici-types: 7.24.6 - - '@types/pako@2.0.4': {} - - '@types/qrcode@1.5.6': - dependencies: - '@types/node': 25.8.0 - - '@types/react-dom@19.2.3(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@types/stats.js@0.17.4': {} - - '@types/three@0.183.1': - dependencies: - '@dimforge/rapier3d-compat': 0.12.0 - '@tweenjs/tween.js': 23.1.3 - '@types/stats.js': 0.17.4 - '@types/webxr': 0.5.24 - '@webgpu/types': 0.1.69 - fflate: 0.8.2 - meshoptimizer: 1.0.1 - - '@types/unist@2.0.11': {} - - '@types/unist@3.0.3': {} - - '@types/webxr@0.5.24': {} - - '@ungap/structured-clone@1.3.0': {} - - '@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1) - transitivePeerDependencies: - - supports-color - - '@webgpu/types@0.1.69': {} - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - autoprefixer@10.4.27(postcss@8.5.8): - dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001780 - fraction.js: 5.3.4 - picocolors: 1.1.1 - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - - bail@2.0.2: {} - - baseline-browser-mapping@2.10.8: {} - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.8 - caniuse-lite: 1.0.30001780 - electron-to-chromium: 1.5.313 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - camelcase@5.3.1: {} - - caniuse-lite@1.0.30001780: {} - - ccount@2.0.1: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - character-reference-invalid@2.0.1: {} - - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - comma-separated-tokens@2.0.3: {} - - convert-source-map@2.0.0: {} - - csstype@3.2.3: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decamelize@1.2.0: {} - - decode-named-character-reference@1.3.0: - dependencies: - character-entities: 2.0.2 - - dequal@2.0.3: {} - - detect-libc@2.1.2: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - dijkstrajs@1.0.3: {} - - electron-to-chromium@1.5.313: {} - - emoji-regex@8.0.0: {} - - enhanced-resolve@5.20.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - entities@6.0.1: {} - - esbuild@0.27.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 - - escalade@3.2.0: {} - - escape-string-regexp@5.0.0: {} - - estree-util-is-identifier-name@3.0.0: {} - - extend@3.0.2: {} - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - fflate@0.8.2: {} - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - fraction.js@5.3.4: {} - - framer-motion@12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - dependencies: - motion-dom: 12.38.0 - motion-utils: 12.36.0 - tslib: 2.8.1 - optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - - fsevents@2.3.3: - optional: true - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - graceful-fs@4.2.11: {} - - hast-util-from-parse5@8.0.3: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - devlop: 1.1.0 - hastscript: 9.0.1 - property-information: 7.1.0 - vfile: 6.0.3 - vfile-location: 5.0.3 - web-namespaces: 2.0.1 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-raw@9.1.0: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - '@ungap/structured-clone': 1.3.0 - hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.1 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - parse5: 7.3.0 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-sanitize@5.0.2: - dependencies: - '@types/hast': 3.0.4 - '@ungap/structured-clone': 1.3.0 - unist-util-position: 5.0.0 - - hast-util-to-jsx-runtime@2.3.6: - dependencies: - '@types/estree': 1.0.8 - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - style-to-js: 1.1.21 - unist-util-position: 5.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - hast-util-to-parse5@8.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hastscript@9.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - - html-parse-stringify@4.0.1: {} - - html-url-attributes@3.0.1: {} - - html-void-elements@3.0.0: {} - - i18next-browser-languagedetector@8.2.1: - dependencies: - '@babel/runtime': 7.29.7 - - i18next@26.4.0(typescript@5.8.3): - optionalDependencies: - typescript: 5.8.3 - - inline-style-parser@0.2.7: {} - - is-alphabetical@2.0.1: {} - - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - - is-decimal@2.0.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-hexadecimal@2.0.1: {} - - is-plain-obj@4.1.0: {} - - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - jsesc@3.1.0: {} - - json5@2.2.3: {} - - lightningcss-android-arm64@1.31.1: - optional: true - - lightningcss-darwin-arm64@1.31.1: - optional: true - - lightningcss-darwin-x64@1.31.1: - optional: true - - lightningcss-freebsd-x64@1.31.1: - optional: true - - lightningcss-linux-arm-gnueabihf@1.31.1: - optional: true - - lightningcss-linux-arm64-gnu@1.31.1: - optional: true - - lightningcss-linux-arm64-musl@1.31.1: - optional: true - - lightningcss-linux-x64-gnu@1.31.1: - optional: true - - lightningcss-linux-x64-musl@1.31.1: - optional: true - - lightningcss-win32-arm64-msvc@1.31.1: - optional: true - - lightningcss-win32-x64-msvc@1.31.1: - optional: true - - lightningcss@1.31.1: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - longest-streak@3.1.0: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - markdown-table@3.0.4: {} - - mdast-util-find-and-replace@3.0.2: - dependencies: - '@types/mdast': 4.0.4 - escape-string-regexp: 5.0.0 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - mdast-util-from-markdown@2.0.3: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-decode-string: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-autolink-literal@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-find-and-replace: 3.0.2 - micromark-util-character: 2.1.1 - - mdast-util-gfm-footnote@2.1.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - micromark-util-normalize-identifier: 2.0.1 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-strikethrough@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-table@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-task-list-item@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm@3.1.0: - dependencies: - mdast-util-from-markdown: 2.0.3 - mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-expression@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-jsx@3.2.0: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - mdast-util-mdxjs-esm@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-phrasing@4.1.0: - dependencies: - '@types/mdast': 4.0.4 - unist-util-is: 6.0.1 - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - - mdast-util-to-markdown@2.1.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - longest-streak: 3.1.0 - mdast-util-phrasing: 4.1.0 - mdast-util-to-string: 4.0.0 - micromark-util-classify-character: 2.0.1 - micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.1.0 - zwitch: 2.0.4 - - mdast-util-to-string@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - - meshoptimizer@1.0.1: {} - - micromark-core-commonmark@2.0.3: - dependencies: - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-factory-destination: 2.0.1 - micromark-factory-label: 2.0.1 - micromark-factory-space: 2.0.1 - micromark-factory-title: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-html-tag-name: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-autolink-literal@2.1.0: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-footnote@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-strikethrough@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-table@2.1.1: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-tagfilter@2.0.0: - dependencies: - micromark-util-types: 2.0.2 - - micromark-extension-gfm-task-list-item@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm@3.0.0: - dependencies: - micromark-extension-gfm-autolink-literal: 2.1.0 - micromark-extension-gfm-footnote: 2.1.0 - micromark-extension-gfm-strikethrough: 2.1.0 - micromark-extension-gfm-table: 2.1.1 - micromark-extension-gfm-tagfilter: 2.0.0 - micromark-extension-gfm-task-list-item: 2.1.0 - micromark-util-combine-extensions: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-destination@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-label@2.0.1: - dependencies: - devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-space@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-types: 2.0.2 - - micromark-factory-title@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-whitespace@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-chunked@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-classify-character@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-combine-extensions@2.0.1: - dependencies: - micromark-util-chunked: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-decode-numeric-character-reference@2.0.2: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-decode-string@2.0.1: - dependencies: - decode-named-character-reference: 1.3.0 - micromark-util-character: 2.1.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-symbol: 2.0.1 - - micromark-util-encode@2.0.1: {} - - micromark-util-html-tag-name@2.0.1: {} - - micromark-util-normalize-identifier@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-resolve-all@2.0.1: - dependencies: - micromark-util-types: 2.0.2 - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-subtokenize@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - micromark@4.0.2: - dependencies: - '@types/debug': 4.1.13 - debug: 4.4.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-combine-extensions: 2.0.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-encode: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - transitivePeerDependencies: - - supports-color - - motion-dom@12.38.0: - dependencies: - motion-utils: 12.36.0 - - motion-utils@12.36.0: {} - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - node-releases@2.0.36: {} - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-try@2.2.0: {} - - pako@2.1.0: {} - - parse-entities@4.0.2: - dependencies: - '@types/unist': 2.0.11 - character-entities-legacy: 3.0.0 - character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.3.0 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - is-hexadecimal: 2.0.1 - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - path-exists@4.0.0: {} - - picocolors@1.1.1: {} - - picomatch@4.0.3: {} - - pngjs@5.0.0: {} - - postcss-value-parser@4.2.0: {} - - postcss@8.5.8: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - property-information@7.1.0: {} - - qrcode@1.5.4: - dependencies: - dijkstrajs: 1.0.3 - pngjs: 5.0.0 - yargs: 15.4.1 - - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - - react-i18next@17.0.12(i18next@26.4.0(typescript@5.8.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.8.3): - dependencies: - '@babel/runtime': 7.29.7 - html-parse-stringify: 4.0.1 - i18next: 26.4.0(typescript@5.8.3) - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) - optionalDependencies: - react-dom: 19.2.4(react@19.2.4) - typescript: 5.8.3 - - react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.4): - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/react': 19.2.14 - devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 - html-url-attributes: 3.0.1 - mdast-util-to-hast: 13.2.1 - react: 19.2.4 - remark-parse: 11.0.0 - remark-rehype: 11.1.2 - unified: 11.0.5 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - - react-refresh@0.17.0: {} - - react@19.2.4: {} - - rehype-raw@7.0.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-raw: 9.1.0 - vfile: 6.0.3 - - rehype-sanitize@6.0.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-sanitize: 5.0.2 - - remark-gfm@4.0.1: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 - micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-parse@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - micromark-util-types: 2.0.2 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-rehype@11.1.2: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - mdast-util-to-hast: 13.2.1 - unified: 11.0.5 - vfile: 6.0.3 - - remark-stringify@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-to-markdown: 2.1.2 - unified: 11.0.5 - - require-directory@2.1.1: {} - - require-main-filename@2.0.0: {} - - rollup@4.59.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 - fsevents: 2.3.3 - - scheduler@0.27.0: {} - - semver@6.3.1: {} - - set-blocking@2.0.0: {} - - source-map-js@1.2.1: {} - - space-separated-tokens@2.0.2: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - style-to-js@1.1.21: - dependencies: - style-to-object: 1.0.14 - - style-to-object@1.0.14: - dependencies: - inline-style-parser: 0.2.7 - - tailwindcss@4.2.1: {} - - tapable@2.3.0: {} - - tauri-plugin-drpc@1.0.3(typescript@5.8.3): - dependencies: - typescript: 5.8.3 - - tauri-plugin-gamepad-api@0.0.5: - dependencies: - '@tauri-apps/api': 2.1.1 - tslib: 2.8.1 - - three@0.183.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - trim-lines@3.0.1: {} - - trough@2.2.0: {} - - tslib@2.8.1: {} - - typescript@5.8.3: {} - - undici-types@7.24.6: {} - - unified@11.0.5: - dependencies: - '@types/unist': 3.0.3 - bail: 2.0.2 - devlop: 1.1.0 - extend: 3.0.2 - is-plain-obj: 4.1.0 - trough: 2.2.0 - vfile: 6.0.3 - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - use-sync-external-store@1.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - - vfile-location@5.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile: 6.0.3 - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vite@7.3.1(@types/node@25.8.0)(jiti@2.6.1)(lightningcss@1.31.1): - dependencies: - esbuild: 0.27.4 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.8 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.8.0 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.31.1 - - web-namespaces@2.0.1: {} - - which-module@2.0.1: {} - - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - y18n@4.0.3: {} - - yallist@3.1.1: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - - zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index efc037a..0000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -onlyBuiltDependencies: - - esbuild diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index 47838e0..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,5 +0,0 @@ -export default { - plugins: { - '@tailwindcss/postcss': {}, - }, -} \ No newline at end of file diff --git a/public/images/lostlegacy_title.png b/public/images/lostlegacy_title.png index 116d426..85a5dff 100644 Binary files a/public/images/lostlegacy_title.png and b/public/images/lostlegacy_title.png differ diff --git a/public/images/tooltips/Durango/A.png b/public/images/tooltips/Durango/A.png new file mode 100644 index 0000000..d3d0d17 Binary files /dev/null and b/public/images/tooltips/Durango/A.png differ diff --git a/public/images/tooltips/Durango/A_BG_S.png b/public/images/tooltips/Durango/A_BG_S.png new file mode 100644 index 0000000..9b57891 Binary files /dev/null and b/public/images/tooltips/Durango/A_BG_S.png differ diff --git a/public/images/tooltips/Durango/B.png b/public/images/tooltips/Durango/B.png new file mode 100644 index 0000000..ef40674 Binary files /dev/null and b/public/images/tooltips/Durango/B.png differ diff --git a/public/images/tooltips/Durango/BG.png b/public/images/tooltips/Durango/BG.png new file mode 100644 index 0000000..ee6a067 Binary files /dev/null and b/public/images/tooltips/Durango/BG.png differ diff --git a/public/images/tooltips/Durango/B_BG_S.png b/public/images/tooltips/Durango/B_BG_S.png new file mode 100644 index 0000000..585e3ab Binary files /dev/null and b/public/images/tooltips/Durango/B_BG_S.png differ diff --git a/public/images/tooltips/Durango/X.png b/public/images/tooltips/Durango/X.png new file mode 100644 index 0000000..4ea0f47 Binary files /dev/null and b/public/images/tooltips/Durango/X.png differ diff --git a/public/images/tooltips/Durango/X_BG_S.png b/public/images/tooltips/Durango/X_BG_S.png new file mode 100644 index 0000000..b8f1508 Binary files /dev/null and b/public/images/tooltips/Durango/X_BG_S.png differ diff --git a/public/music/Moog City 2.ogg b/public/music/Moog City 2.ogg new file mode 100644 index 0000000..9625f69 Binary files /dev/null and b/public/music/Moog City 2.ogg differ diff --git a/public/music/Moog City 2.opus b/public/music/Moog City 2.opus deleted file mode 100644 index 7465f4e..0000000 Binary files a/public/music/Moog City 2.opus and /dev/null differ diff --git a/public/panorama/legacyorbis_Panorama_Background_Day.png b/public/panorama/legacyorbis_Panorama_Background_Day.png index 1760c0c..3e11842 100644 Binary files a/public/panorama/legacyorbis_Panorama_Background_Day.png and b/public/panorama/legacyorbis_Panorama_Background_Day.png differ diff --git a/public/panorama/legacyorbis_Panorama_Background_Night.png b/public/panorama/legacyorbis_Panorama_Background_Night.png index 2cf58ff..48b0fcc 100644 Binary files a/public/panorama/legacyorbis_Panorama_Background_Night.png and b/public/panorama/legacyorbis_Panorama_Background_Night.png differ diff --git a/public/panorama/vanilla_tu19_Panorama_Background_Day.png b/public/panorama/vanilla_tu19_Panorama_Background_Day.png index c719315..56ca66a 100644 Binary files a/public/panorama/vanilla_tu19_Panorama_Background_Day.png and b/public/panorama/vanilla_tu19_Panorama_Background_Day.png differ diff --git a/public/panorama/vanilla_tu19_Panorama_Background_Night.png b/public/panorama/vanilla_tu19_Panorama_Background_Night.png index 8e597f6..618fd7f 100644 Binary files a/public/panorama/vanilla_tu19_Panorama_Background_Night.png and b/public/panorama/vanilla_tu19_Panorama_Background_Night.png differ diff --git a/public/panorama/vanilla_tu24_Panorama_Background_Day.png b/public/panorama/vanilla_tu24_Panorama_Background_Day.png index 1760c0c..579e3fc 100644 Binary files a/public/panorama/vanilla_tu24_Panorama_Background_Day.png and b/public/panorama/vanilla_tu24_Panorama_Background_Day.png differ diff --git a/public/panorama/vanilla_tu24_Panorama_Background_Night.png b/public/panorama/vanilla_tu24_Panorama_Background_Night.png index 2cf58ff..a9367bc 100644 Binary files a/public/panorama/vanilla_tu24_Panorama_Background_Night.png and b/public/panorama/vanilla_tu24_Panorama_Background_Night.png differ diff --git a/public/sounds/click.wav b/public/sounds/click.wav deleted file mode 100644 index 0b70857..0000000 Binary files a/public/sounds/click.wav and /dev/null differ diff --git a/src-tauri/resources/DLC/Emerald Skin Pack/Skins1.pck b/resources/DLC/Emerald Skin Pack/Skins1.pck similarity index 100% rename from src-tauri/resources/DLC/Emerald Skin Pack/Skins1.pck rename to resources/DLC/Emerald Skin Pack/Skins1.pck diff --git a/src-tauri/resources/SDL2.dll b/resources/SDL2.dll similarity index 100% rename from src-tauri/resources/SDL2.dll rename to resources/SDL2.dll diff --git a/src/i18n/locales/en.json b/resources/i18n/en.json similarity index 99% rename from src/i18n/locales/en.json rename to resources/i18n/en.json index bc3c0d2..0a22ad0 100644 --- a/src/i18n/locales/en.json +++ b/resources/i18n/en.json @@ -141,6 +141,8 @@ }, "versions": { "title": "Versions", + "play": "Play", + "stop": "Stop", "custom": "Custom", "updateAvailable": "Update Available!", "repair": "Repair", diff --git a/src/i18n/locales/fr.json b/resources/i18n/fr.json similarity index 99% rename from src/i18n/locales/fr.json rename to resources/i18n/fr.json index f6278d7..8bcbb84 100644 --- a/src/i18n/locales/fr.json +++ b/resources/i18n/fr.json @@ -141,6 +141,8 @@ }, "versions": { "title": "Versions", + "play": "Jouer", + "stop": "Arrêter", "custom": "Modifié", "updateAvailable": "Mise à jour disponible!", "repair": "Réparer", diff --git a/src/i18n/locales/ru.json b/resources/i18n/ru.json similarity index 99% rename from src/i18n/locales/ru.json rename to resources/i18n/ru.json index bc37845..ce64a0a 100644 --- a/src/i18n/locales/ru.json +++ b/resources/i18n/ru.json @@ -141,6 +141,8 @@ }, "versions": { "title": "Версии", + "play": "Играть", + "stop": "Остановить", "custom": "Кастомные", "updateAvailable": "Доступно обновление!", "repair": "Ремонт", diff --git a/scripts/build-goldmapper.mjs b/scripts/build-goldmapper.mjs deleted file mode 100644 index 41a4cc6..0000000 --- a/scripts/build-goldmapper.mjs +++ /dev/null @@ -1,76 +0,0 @@ -import { spawnSync } from "node:child_process"; -import { existsSync, copyFileSync, mkdirSync, readdirSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url)); -const ROOT_DIR = path.resolve(SCRIPT_DIR, ".."); -const GOLDMAPPER_DIR = path.join(ROOT_DIR, "GoldMapper"); -const BUILD_DIR = path.join(GOLDMAPPER_DIR, "build"); -const RESOURCES_DIR = path.join(ROOT_DIR, "src-tauri", "resources"); -const TOOLCHAIN_MINGW = path.join(SCRIPT_DIR, "toolchain-mingw.cmake"); -const IS_WINDOWS = process.platform === "win32"; -function run(cmd, args, cwd) { - console.log(`> ${cmd} ${args.join(" ")}`); - const res = spawnSync(cmd, args, { - cwd, - stdio: "inherit", - shell: IS_WINDOWS, - }); - if (res.status !== 0) { - process.exit(res.status ?? 1); - } -} - -if ( - !existsSync( - path.join(GOLDMAPPER_DIR, "third_party", "minhook", "include", "MinHook.h"), - ) -) { - console.log("Initializing minhook submodule..."); - run( - "git", - ["-C", GOLDMAPPER_DIR, "submodule", "update", "--init", "--recursive"], - ROOT_DIR, - ); -} - -console.log("Configuring GoldMapper..."); -const configureArgs = ["-B", BUILD_DIR, "-DCMAKE_BUILD_TYPE=Release"]; -if (!IS_WINDOWS) { - configureArgs.push("-DCMAKE_TOOLCHAIN_FILE=" + TOOLCHAIN_MINGW); -} -configureArgs.push(GOLDMAPPER_DIR); -run("cmake", configureArgs, ROOT_DIR); -console.log("Building GoldMapper..."); -run("cmake", ["--build", BUILD_DIR, "--config", "Release"], ROOT_DIR); -console.log("Copying binaries to resources..."); -mkdirSync(RESOURCES_DIR, { recursive: true }); -const outputs = [ - { - source: "GoldMapperLib.dll", - names: ["GoldMapperLib.dll", "libGoldMapperLib.dll"], //neo: dont ask me vro idk why it does that - }, - { source: "GoldMapperLauncher.exe", names: ["GoldMapperLauncher.exe"] }, -]; - -for (const entry of outputs) { - const dir = entry.dir ?? BUILD_DIR; - const file = path.join(dir, entry.source); - if (existsSync(file)) { - copyFileSync(file, path.join(RESOURCES_DIR, entry.source)); - continue; - } - const candidate = readdirSync(dir).find((f) => - entry.names.some((n) => f.toLowerCase() === n.toLowerCase()), - ); - if (!candidate) { - console.error(`Missing build output: ${entry.source}`); - process.exit(1); - } - copyFileSync( - path.join(dir, candidate), - path.join(RESOURCES_DIR, entry.source), - ); -} - -console.log("GoldMapper build complete."); diff --git a/scripts/download-android-assets.mjs b/scripts/download-android-assets.mjs deleted file mode 100644 index 5306983..0000000 --- a/scripts/download-android-assets.mjs +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env node -import { - createWriteStream, - createReadStream, - existsSync, - unlinkSync, -} from "node:fs"; -import { mkdir, rename } from "node:fs/promises"; -import { createHash } from "node:crypto"; -import { Readable } from "node:stream"; -import { fileURLToPath } from "node:url"; -import path from "node:path"; -const RELEASE_TAG = "android-assets-v1"; -const REPO = "LCE-Hub/LCE-Emerald-Launcher"; -const ASSET_DIR = fileURLToPath( - new URL("../src-tauri/gen/android/app/src/main/assets/", import.meta.url), -); - -const ASSETS = [ - { - file: "imagefs.tar.zst", - sha256: "7838756e6a05c91afff68f4bf12aa2780f815877753f8dd354e203e99b9caf8a", - }, - { - file: "proton-11.0-arm64ec.tar.zst", - sha256: "ceb768396c2d44256518f94ae236f0c1f40738cf050a52e990e2fef67ff161df", - }, -]; - -function sha256File(file) { - return new Promise((resolve, reject) => { - const hash = createHash("sha256"); - const stream = createReadStream(file); - stream.on("data", (chunk) => hash.update(chunk)); - stream.on("end", () => resolve(hash.digest("hex"))); - stream.on("error", reject); - }); -} - -async function download(url, dest) { - const res = await fetch(url, { redirect: "follow" }); - if (!res.ok) { - throw new Error(`HTTP ${res.status} ${res.statusText} for ${url}`); - } - - if (!res.body) { - throw new Error(`no response body for ${url}`); - } - - const fileStream = createWriteStream(dest); - await new Promise((resolve, reject) => { - const body = Readable.fromWeb(res.body); - body.pipe(fileStream); - body.on("error", reject); - fileStream.on("finish", resolve); - fileStream.on("error", reject); - }); -} - -let failed = false; -for (const asset of ASSETS) { - const target = path.join(ASSET_DIR, asset.file); - if (existsSync(target)) { - const actual = await sha256File(target); - if (actual === asset.sha256) { - console.log(`okay ${asset.file} (up to date)`); - continue; - } - - console.error( - `error ${asset.file}: sha256 mismatch (expected ${asset.sha256}, got ${actual}); delete it and rerun`, - ); - - failed = true; - continue; - } - - const url = `https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${asset.file}`; - console.log(`get ${asset.file} <- ${url}`); - await mkdir(path.dirname(target), { recursive: true }); - const tmp = target + ".part"; - try { - await download(url, tmp); - const actual = await sha256File(tmp); - if (actual !== asset.sha256) { - console.error( - `error ${asset.file}: downloaded sha256 mismatch (expected ${asset.sha256}, got ${actual})`, - ); - - failed = true; - if (existsSync(tmp)) { - unlinkSync(tmp); - } - - continue; - } - - await rename(tmp, target); - console.log(`okay ${asset.file} (downloaded)`); - } catch (error) { - console.error(`error ${asset.file}: ${error.message}`); - failed = true; - if (existsSync(tmp)) { - unlinkSync(tmp); - } - } -} - -process.exit(failed ? 1 : 0); diff --git a/scripts/fix-macos-quarantine.sh b/scripts/fix-macos-quarantine.sh deleted file mode 100755 index 52d2617..0000000 --- a/scripts/fix-macos-quarantine.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Fix macOS quarantine issue for ARM builds fuck apple man -# This script removes quarantine attributes from the built app - -set -e - -APP_PATH="$1" -BUNDLE_ID="com.emerald.legacy" - -if [ -z "$APP_PATH" ]; then - echo "Usage: $0 " - exit 1 -fi - -if [ ! -d "$APP_PATH" ]; then - echo "Error: App bundle not found at $APP_PATH" - exit 1 -fi - -echo "Fixing macOS quarantine for: $APP_PATH" - -# Remove quarantine attributes -xattr -cr "$APP_PATH" - -# Add basic code signing (ad-hoc signature) -codesign --force --deep --sign - "$APP_PATH" 2>/dev/null || { - echo "Warning: Code signing failed, but quarantine removal should work" -} - -echo "macOS quarantine fix completed" -echo "The app should now launch without 'damaged' error" diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh deleted file mode 100755 index 67d968d..0000000 --- a/scripts/postinstall.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Post-install script for PKG installer -# Automatically removes quarantine attributes from the installed app - -APP_PATH="$2/Applications/Emerald Legacy Launcher.app" - -echo "Removing quarantine attributes from Emerald Legacy Launcher..." - -if [ -d "$APP_PATH" ]; then - xattr -cr "$APP_PATH" - echo "Quarantine attributes removed successfully." - exit 0 -else - echo "Warning: App not found at expected location: $APP_PATH" - exit 1 -fi diff --git a/scripts/toolchain-mingw.cmake b/scripts/toolchain-mingw.cmake deleted file mode 100644 index b4a1291..0000000 --- a/scripts/toolchain-mingw.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(CMAKE_SYSTEM_NAME Windows) -set(CMAKE_SYSTEM_PROCESSOR x86_64) -set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) -set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) -set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) \ No newline at end of file diff --git a/scripts/update-homebrew.py b/scripts/update-homebrew.py deleted file mode 100644 index 6b1ad72..0000000 --- a/scripts/update-homebrew.py +++ /dev/null @@ -1,81 +0,0 @@ -import argparse -import re -import os - -def update_stable(version, intel_hash, arm_hash, linux_hash): - cask_path = "Casks/lce-emerald-launcher.rb" - formula_path = "Formula/lce-emerald-launcher.rb" - - # Update Cask - if os.path.exists(cask_path): - with open(cask_path, 'r') as f: - content = f.read() - - # Replace version - content = re.sub(r'^\s*version\s+"[^"]+"', f' version "{version}"', content, flags=re.MULTILINE) - # Replace sha256 block - content = re.sub(r'sha256\s+intel:\s+"[a-f0-9]+",\r?\n\s+arm:\s+"[a-f0-9]+"', - f'sha256 intel: "{intel_hash}",\n arm: "{arm_hash}"', - content) - - with open(cask_path, 'w') as f: - f.write(content) - print(f"Updated {cask_path}") - else: - print(f"Error: {cask_path} not found") - - # Update Formula - if os.path.exists(formula_path): - with open(formula_path, 'r') as f: - content = f.read() - - # Replace version - content = re.sub(r'^\s*version\s+"[^"]+"', f' version "{version}"', content, flags=re.MULTILINE) - # Replace sha256 - content = re.sub(r'^\s*sha256\s+"[a-f0-9]+"', f' sha256 "{linux_hash}"', content, flags=re.MULTILINE) - - with open(formula_path, 'w') as f: - f.write(content) - print(f"Updated {formula_path}") - else: - print(f"Error: {formula_path} not found") - -def update_experimental(version, intel_hash, arm_hash): - cask_path = "Casks/lce-emerald-launcher-experimental.rb" - - if os.path.exists(cask_path): - with open(cask_path, 'r') as f: - content = f.read() - - # Replace version - content = re.sub(r'^\s*version\s+"[^"]+"', f' version "{version}"', content, flags=re.MULTILINE) - # Replace sha256 block - content = re.sub(r'sha256\s+intel:\s+"[a-f0-9]+",\r?\n\s+arm:\s+"[a-f0-9]+"', - f'sha256 intel: "{intel_hash}",\n arm: "{arm_hash}"', - content) - - with open(cask_path, 'w') as f: - f.write(content) - print(f"Updated {cask_path}") - else: - print(f"Error: {cask_path} not found") - -def main(): - parser = argparse.ArgumentParser(description="Update Homebrew Formula/Cask files") - parser.add_argument("--type", choices=["stable" ], required=True) - parser.add_argument("--version", required=True) - parser.add_argument("--intel-hash", required=True) - parser.add_argument("--arm-hash", required=True) - parser.add_argument("--linux-hash") - - args = parser.parse_args() - - if args.type == "stable": - if not args.linux_hash: - raise ValueError("--linux-hash is required for stable update") - update_stable(args.version, args.intel_hash, args.arm_hash, args.linux_hash) - elif args.type == "experimental": - update_experimental(args.version, args.intel_hash, args.arm_hash) - -if __name__ == "__main__": - main() diff --git a/scripts/update-nix-stable.py b/scripts/update-nix-stable.py deleted file mode 100644 index c6b10d8..0000000 --- a/scripts/update-nix-stable.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import re -import sys - - -def update_flake(version: str, src_hash: str) -> None: - path = "flake.nix" - with open(path, "r", encoding="utf-8") as f: - content = f.read() - - new_content, n_version = re.subn( - r'stableVersion = "[^"]*";', - f'stableVersion = "{version}";', - content, - count=1, - ) - new_content, n_hash = re.subn( - r'stableSrcHash = "[^"]*";', - f'stableSrcHash = "{src_hash}";', - new_content, - count=1, - ) - - if n_version != 1 or n_hash != 1: - print( - f"Error: expected to update stableVersion and stableSrcHash once each " - f"(got version={n_version}, hash={n_hash})", - file=sys.stderr, - ) - sys.exit(1) - - with open(path, "w", encoding="utf-8") as f: - f.write(new_content) - - print(f"Updated {path}: stableVersion={version} stableSrcHash={src_hash}") - - -def main() -> None: - parser = argparse.ArgumentParser( - description="Update flake.nix stableVersion and stableSrcHash" - ) - parser.add_argument("--version", required=True, help="Stable version without v prefix") - parser.add_argument("--src-hash", required=True, help="SRI sha256 of the release source") - args = parser.parse_args() - update_flake(args.version, args.src_hash) - - -if __name__ == "__main__": - main() diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore deleted file mode 100644 index d8769d0..0000000 --- a/src-tauri/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - -# Generated by Tauri -# will have schema files for capabilities auto-completion -/gen/schemas diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock deleted file mode 100644 index 70dbfe2..0000000 --- a/src-tauri/Cargo.lock +++ /dev/null @@ -1,7130 +0,0 @@ -# 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.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "ashpd" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f3f79755c74fd155000314eb349864caa787c6592eace6c6882dad873d9c39" -dependencies = [ - "async-fs", - "async-net", - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.9.2", - "raw-window-handle", - "serde", - "serde_repr", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus", -] - -[[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.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[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-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-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.117", -] - -[[package]] -name = "async-signal" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" -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.117", -] - -[[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 = "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 = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - -[[package]] -name = "bit_field" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -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.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "bytecount" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" - -[[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 = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[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.11.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.12+spec-1.1.0", -] - -[[package]] -name = "cc" -version = "1.2.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" -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 1.23.0", -] - -[[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 = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "num-traits", - "serde", - "windows-link 0.2.1", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[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 = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom 0.2.17", - "once_cell", - "tiny-keccak", -] - -[[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.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.10.1", - "core-graphics-types", - "foreign-types", - "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.11.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-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -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 = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[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" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.13.1", - "smallvec", -] - -[[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.117", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.117", -] - -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "data-encoding" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" - -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", - "serde_core", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[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.117", -] - -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.117", -] - -[[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 = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[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", - "windows-sys 0.61.2", -] - -[[package]] -name = "dispatch2" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" -dependencies = [ - "bitflags 2.11.0", - "block2", - "libc", - "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.117", -] - -[[package]] -name = "dlib" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" -dependencies = [ - "libloading 0.8.9", -] - -[[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.117", -] - -[[package]] -name = "dlv-list" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" -dependencies = [ - "const-random", -] - -[[package]] -name = "dom_query" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" -dependencies = [ - "bit-set", - "cssparser 0.36.0", - "foldhash 0.2.0", - "html5ever 0.38.0", - "precomputed-hash", - "selectors 0.36.1", - "tendril 0.5.0", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[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 = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embed-resource" -version = "3.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63a1d0de4f2249aa0ff5884d7080814f446bb241a559af6c170a41e878ed2d45" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.12+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 = "emerald-legacy-launcher" -version = "1.6.1" -dependencies = [ - "base64 0.21.7", - "byteorder", - "flate2", - "futures-util", - "http 1.4.0", - "image 0.24.9", - "jni", - "libc", - "lzxd", - "once_cell", - "rand 0.8.5", - "reqwest 0.11.27", - "rfd", - "serde", - "serde_json", - "steam_shortcuts_util", - "tauri", - "tauri-build", - "tauri-plugin-deep-link", - "tauri-plugin-drpc", - "tauri-plugin-gamepad", - "tauri-plugin-opener", - "tauri-plugin-process", - "tauri-plugin-single-instance", - "tauri-plugin-updater", - "tokio", - "tokio-tungstenite", - "tokio-util", - "url", - "uuid 1.23.0", - "wry", -] - -[[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 = "enum-iterator" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" -dependencies = [ - "enum-iterator-derive", -] - -[[package]] -name = "enum-iterator-derive" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[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.117", -] - -[[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.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" -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 = "exr" -version = "1.74.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[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 = "filetime" -version = "0.2.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5b2eef6fafbf69f877e55509ce5b11a760690ac9700a2921be067aa6afaef6" -dependencies = [ - "cfg-if", - "libc", -] - -[[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 = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[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", -] - -[[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.117", -] - -[[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.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[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.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "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 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - -[[package]] -name = "gif" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "gilrs" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa85c2e35dc565c90511917897ea4eae16b77f2773d5223536f7b602536d462" -dependencies = [ - "fnv", - "gilrs-core", - "log", - "serde", - "uuid 1.23.0", - "vec_map", -] - -[[package]] -name = "gilrs-core" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23f2cc5144060a7f8d9e02d3fce5d06705376568256a509cdbc3c24d47e4f04" -dependencies = [ - "inotify", - "js-sys", - "libc", - "libudev-sys", - "log", - "nix", - "objc2-core-foundation", - "objc2-io-kit", - "serde", - "uuid 1.23.0", - "vec_map", - "wasm-bindgen", - "web-sys", - "windows 0.62.2", -] - -[[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.11.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.117", -] - -[[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.117", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.13.1", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - -[[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 0.14.1", - "match_token", -] - -[[package]] -name = "html5ever" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" -dependencies = [ - "log", - "markup5ever 0.38.0", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[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 = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.4.0", -] - -[[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 1.4.0", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http 1.4.0", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" -dependencies = [ - "http 1.4.0", - "hyper 1.9.0", - "hyper-util", - "rustls 0.23.40", - "tokio", - "tokio-rustls 0.26.4", - "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 1.4.0", - "http-body 1.0.1", - "hyper 1.9.0", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", -] - -[[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 0.17.16", -] - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[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 = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "exr", - "gif", - "jpeg-decoder", - "num-traits", - "png 0.17.16", - "qoi", - "tiff", -] - -[[package]] -name = "image" -version = "0.25.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "png 0.18.1", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" -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 = "inotify" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" -dependencies = [ - "bitflags 2.11.0", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "ipnet" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "iri-string" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-docker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] - -[[package]] -name = "is-wsl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" -dependencies = [ - "is-docker", - "once_cell", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[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 0.3.1", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" -dependencies = [ - "jni-sys 0.4.1", -] - -[[package]] -name = "jni-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" -dependencies = [ - "jni-sys-macros", -] - -[[package]] -name = "jni-sys-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" -dependencies = [ - "rayon", -] - -[[package]] -name = "js-sys" -version = "0.3.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" -dependencies = [ - "cfg-if", - "futures-util", - "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.11.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 0.29.6", - "html5ever 0.29.1", - "indexmap 2.13.1", - "selectors 0.24.0", -] - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lebe" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" - -[[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 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.184" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" - -[[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 = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - -[[package]] -name = "libredox" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" -dependencies = [ - "libc", -] - -[[package]] -name = "libudev-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[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 = "lzxd" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b29dffab797218e12e4df08ef5d15ab9efca2504038b1b32b9b32fc844b39c9" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[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 0.8.9", - "string_cache_codegen 0.5.4", - "tendril 0.4.3", -] - -[[package]] -name = "markup5ever" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" -dependencies = [ - "log", - "tendril 0.5.0", - "web_atoms", -] - -[[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.117", -] - -[[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 = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "minisign-verify" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" - -[[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.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.61.2", -] - -[[package]] -name = "moxcms" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" -dependencies = [ - "num-traits", - "pxfm", -] - -[[package]] -name = "muda" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9fec5a4e89860383d778d10563a605838f8f0b2f9303868937e5ff32e86177" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation", - "once_cell", - "png 0.17.16", - "serde", - "thiserror 2.0.18", - "windows-sys 0.60.2", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.11.0", - "jni-sys 0.3.1", - "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 0.3.1", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.11.0", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nom_locate" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3" -dependencies = [ - "bytecount", - "memchr", - "nom", -] - -[[package]] -name = "num-conv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" - -[[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.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "objc2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" -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.11.0", - "block2", - "objc2", - "objc2-core-foundation", - "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.11.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.11.0", - "dispatch2", - "objc2", - "objc2-core-foundation", - "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.11.0", - "block2", - "libc", - "objc2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" -dependencies = [ - "bitflags 2.11.0", - "libc", - "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.11.0", - "objc2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-osa-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-app-kit", - "objc2-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.11.0", - "objc2", - "objc2-core-foundation", - "objc2-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.11.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.11.0", - "block2", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "open" -version = "5.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" -dependencies = [ - "dunce", - "is-wsl", - "libc", - "pathdiff", -] - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-multimap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" -dependencies = [ - "dlv-list", - "hashbrown 0.14.5", -] - -[[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 = "osakit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" -dependencies = [ - "objc2", - "objc2-foundation", - "objc2-osa-kit", - "serde", - "serde_json", - "thiserror 2.0.18", -] - -[[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 = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - -[[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" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" -dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", - "serde", -] - -[[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_codegen" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" -dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - -[[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_generator" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" -dependencies = [ - "fastrand", - "phf_shared 0.13.1", -] - -[[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.117", -] - -[[package]] -name = "phf_macros" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" -dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[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 = "phf_shared" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" -dependencies = [ - "siphasher 1.0.2", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "piper" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" -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.1", - "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 = "png" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" -dependencies = [ - "bitflags 2.11.0", - "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 = "pollster" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -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 = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - -[[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.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit 0.25.11+spec-1.1.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 = "pxfm" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-xml" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.39.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -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 = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[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 = "rayon" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.11.0", -] - -[[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.117", -] - -[[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.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-rustls 0.24.1", - "tokio-socks", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.4.2", - "web-sys", - "webpki-roots 0.25.4", - "winreg 0.50.0", -] - -[[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 1.4.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.9.0", - "hyper-rustls 0.27.9", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "rustls 0.23.40", - "rustls-pki-types", - "rustls-platform-verifier", - "serde", - "serde_json", - "sync_wrapper 1.0.2", - "tokio", - "tokio-rustls 0.26.4", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.5.0", - "web-sys", -] - -[[package]] -name = "rfd" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" -dependencies = [ - "ashpd", - "block2", - "dispatch2", - "js-sys", - "log", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation", - "pollster", - "raw-window-handle", - "urlencoding", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.59.0", -] - -[[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 = "rpcdiscord" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71aa9a2097dc0176805e24debcb5d3ea5a17b796cd1d28e76b29f78fb49d7d5d" -dependencies = [ - "serde", - "serde_derive", - "serde_json", - "serde_repr", - "uuid 0.8.2", -] - -[[package]] -name = "rust-ini" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" -dependencies = [ - "cfg-if", - "ordered-multimap", -] - -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags 2.11.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki 0.102.8", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki 0.103.13", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls 0.23.40", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki 0.103.13", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -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.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -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 1.23.0", -] - -[[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.117", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -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 0.29.6", - "derive_more 0.99.20", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc 0.2.0", - "smallvec", -] - -[[package]] -name = "selectors" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" -dependencies = [ - "bitflags 2.11.0", - "cssparser 0.36.0", - "derive_more 2.1.1", - "log", - "new_debug_unreachable", - "phf 0.13.1", - "phf_codegen 0.13.1", - "precomputed-hash", - "rustc-hash", - "servo_arc 0.4.3", - "smallvec", -] - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" -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.117", -] - -[[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.117", -] - -[[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.117", -] - -[[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.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" -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.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.13.1", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[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.117", -] - -[[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 = "servo_arc" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[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.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.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 = "steam_shortcuts_util" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0543ebdb23a93b196aceebc53f70cc5a573bb74248a974b3f5fa3883e6a89b6" -dependencies = [ - "ascii", - "crc32fast", - "nom", - "nom_locate", -] - -[[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" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.13.1", - "precomputed-hash", -] - -[[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 = "string_cache_codegen" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" -dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", - "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.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[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.117", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" -dependencies = [ - "bitflags 2.11.0", - "block2", - "core-foundation 0.10.1", - "core-graphics", - "crossbeam-channel", - "dispatch2", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2", - "objc2-app-kit", - "objc2-foundation", - "once_cell", - "parking_lot", - "raw-window-handle", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tar" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[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.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" -dependencies = [ - "anyhow", - "bytes", - "cookie", - "dirs", - "dunce", - "embed_plist", - "getrandom 0.3.4", - "glob", - "gtk", - "heck 0.5.0", - "http 1.4.0", - "http-range", - "image 0.25.10", - "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 0.61.3", -] - -[[package]] -name = "tauri-build" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs", - "glob", - "heck 0.5.0", - "json-patch", - "schemars 0.8.22", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.9.12+spec-1.1.0", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png 0.17.16", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.117", - "tauri-utils", - "thiserror 2.0.18", - "time", - "url", - "uuid 1.23.0", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri-utils", - "toml 0.9.12+spec-1.1.0", - "walkdir", -] - -[[package]] -name = "tauri-plugin-deep-link" -version = "2.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ee75bc5627f77bfdf40c913255ebc258117b10ebe2b2239a1a1cf40b0b58aa" -dependencies = [ - "dunce", - "plist", - "rust-ini", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.18", - "tracing", - "url", - "windows-registry", - "windows-result 0.3.4", -] - -[[package]] -name = "tauri-plugin-drpc" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b291669b7dbc05471fba380eeecf31e3f733ae6013aaa5216a43ca376027e5a" -dependencies = [ - "log", - "rpcdiscord", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.18", - "tokio", -] - -[[package]] -name = "tauri-plugin-gamepad" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2cabe60f9c36a3fa85323b56be22074f7dd5fa691dc17467e09882cd8d10d2" -dependencies = [ - "enum-iterator", - "gilrs", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.18", - "uuid 1.23.0", -] - -[[package]] -name = "tauri-plugin-opener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc624469b06f59f5a29f874bbc61a2ed737c0f9c23ef09855a292c389c42e83f" -dependencies = [ - "dunce", - "glob", - "objc2-app-kit", - "objc2-foundation", - "open", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.18", - "url", - "windows 0.61.3", - "zbus", -] - -[[package]] -name = "tauri-plugin-process" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" -dependencies = [ - "tauri", - "tauri-plugin", -] - -[[package]] -name = "tauri-plugin-single-instance" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8f29386f5e9fdc699182388a33ee80a56de436d91b67459e86afef426282af" -dependencies = [ - "serde", - "serde_json", - "tauri", - "thiserror 2.0.18", - "tracing", - "windows-sys 0.60.2", - "zbus", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af" -dependencies = [ - "base64 0.22.1", - "dirs", - "flate2", - "futures-util", - "http 1.4.0", - "infer", - "log", - "minisign-verify", - "osakit", - "percent-encoding", - "reqwest 0.13.2", - "rustls 0.23.40", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror 2.0.18", - "time", - "tokio", - "url", - "windows-sys 0.60.2", - "zip", -] - -[[package]] -name = "tauri-runtime" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http 1.4.0", - "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 0.61.3", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" -dependencies = [ - "gtk", - "http 1.4.0", - "jni", - "log", - "objc2", - "objc2-app-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever 0.29.1", - "http 1.4.0", - "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.12+spec-1.1.0", - "url", - "urlpattern", - "uuid 1.23.0", - "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.12+spec-1.1.0", -] - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "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 = "tendril" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" -dependencies = [ - "new_debug_unreachable", - "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.117", -] - -[[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.117", -] - -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - -[[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 = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.6.3", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" -dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls 0.23.40", - "tokio", -] - -[[package]] -name = "tokio-socks" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e2948f60dbe26b35f2c7fb74ac2854c1fddded0fe9d7548fcc674a246f7615" -dependencies = [ - "either", - "futures-util", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "rustls 0.22.4", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.25.0", - "tungstenite", - "webpki-roots 0.26.11", -] - -[[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", - "futures-util", - "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.12+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" -dependencies = [ - "indexmap 2.13.1", - "serde_core", - "serde_spanned 1.1.1", - "toml_datetime 0.7.5+spec-1.1.0", - "toml_parser", - "toml_writer", - "winnow 0.7.15", -] - -[[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_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -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.1", - "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.1", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.25.11+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" -dependencies = [ - "indexmap 2.13.1", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "winnow 1.0.1", -] - -[[package]] -name = "toml_parser" -version = "1.1.3+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" -dependencies = [ - "winnow 1.0.1", -] - -[[package]] -name = "toml_writer" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" - -[[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 1.0.2", - "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.11.0", - "bytes", - "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "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.117", -] - -[[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", - "libappindicator", - "muda", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation", - "once_cell", - "png 0.17.16", - "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 = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.22.4", - "rustls-pki-types", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", -] - -[[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.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" -dependencies = [ - "memoffset", - "tempfile", - "windows-sys 0.61.2", -] - -[[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.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[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 = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[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 = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "uuid" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" -dependencies = [ - "getrandom 0.4.2", - "js-sys", - "serde_core", - "wasm-bindgen", -] - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[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 = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.117", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.1", - "wasm-encoder", - "wasmparser", -] - -[[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 = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.15.5", - "indexmap 2.13.1", - "semver", -] - -[[package]] -name = "wayland-backend" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" -dependencies = [ - "bitflags 2.11.0", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" -dependencies = [ - "bitflags 2.11.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" -dependencies = [ - "proc-macro2", - "quick-xml 0.39.2", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - -[[package]] -name = "web-sys" -version = "0.3.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web_atoms" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" -dependencies = [ - "phf 0.13.1", - "phf_codegen 0.13.1", - "string_cache 0.9.0", - "string_cache_codegen 0.6.1", -] - -[[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 = "webpki-root-certs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.9", -] - -[[package]] -name = "webpki-roots" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" -dependencies = [ - "rustls-pki-types", -] - -[[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 0.61.3", - "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.117", -] - -[[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 0.61.3", - "windows-core 0.61.2", -] - -[[package]] -name = "weezl" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" - -[[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.48.0", -] - -[[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 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", - "windows-link 0.1.3", - "windows-numerics 0.2.0", -] - -[[package]] -name = "windows" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" -dependencies = [ - "windows-collections 0.3.2", - "windows-core 0.62.2", - "windows-future 0.3.2", - "windows-numerics 0.3.1", -] - -[[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-collections" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" -dependencies = [ - "windows-core 0.62.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 0.1.0", -] - -[[package]] -name = "windows-future" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", - "windows-threading 0.2.1", -] - -[[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.117", -] - -[[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.117", -] - -[[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-numerics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", -] - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[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.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[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-threading" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" -dependencies = [ - "windows-link 0.2.1", -] - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[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.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[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" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.13.1", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.1", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.1", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "wry" -version = "0.54.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" -dependencies = [ - "base64 0.22.1", - "block2", - "cookie", - "crossbeam-channel", - "dirs", - "dom_query", - "dpi", - "dunce", - "gdkx11", - "gtk", - "http 1.4.0", - "javascriptcore-rs", - "jni", - "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 0.61.3", - "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 = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix", -] - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zbus" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" -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 1.23.0", - "windows-sys 0.61.2", - "winnow 0.7.15", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", - "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.15", - "zvariant", -] - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zip" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" -dependencies = [ - "arbitrary", - "crc32fast", - "indexmap 2.13.1", - "memchr", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "zvariant" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" -dependencies = [ - "endi", - "enumflags2", - "serde", - "url", - "winnow 0.7.15", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", - "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.117", - "winnow 0.7.15", -] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml deleted file mode 100644 index e275f51..0000000 --- a/src-tauri/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "emerald-legacy-launcher" -version = "1.6.1" -description = "A FOSS, cross-platform launcher for Minecraft Legacy Edition" -authors = ["Emerald Team"] -edition = "2024" - -[lib] -name = "emerald_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -tauri = { version = "2", features = ["protocol-asset", "tray-icon", "image-png"] } -tauri-plugin-opener = "2" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tauri-plugin-gamepad = "0.0.5" -reqwest = { version = "0.11", default-features = false, features = ["stream", "json", "rustls-tls-webpki-roots", "socks"] } -tokio = { version = "1", features = ["full"] } -futures-util = "0.3" -tokio-util = { version = "0.7.18", features = ["rt"] } -base64 = "0.21" -tokio-tungstenite = { version = "0.21", default-features = false, features = ["connect", "rustls-tls-webpki-roots"] } -url = "2" -rand = "0.8" -http = "1" -libc = "0.2" -image = "0.24" -steam_shortcuts_util = "1.1.8" -tauri-plugin-process = "2" -byteorder = "1" -flate2 = "1" -once_cell = "1" -lzxd = "0.2.6" -uuid = { version = "1", features = ["v4"] } -tauri-plugin-deep-link = "2" - -[target.'cfg(target_os = "android")'.dependencies] -wry = { version = "0.54", default-features = false } -jni = "0.21" - -[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] -tauri-plugin-updater = "2" -tauri-plugin-drpc = "*" -tauri-plugin-single-instance = "2" -rfd = "0.15" - -#neo: enable portable appimages. revert back to crates.io once the PR is merged -#[patch.crates-io] -#tauri = { git = "https://github.com/tauri-apps/tauri", branch = "feat/truly-portable-appimage" } -#end neo diff --git a/src-tauri/build.rs b/src-tauri/build.rs deleted file mode 100644 index 158c051..0000000 --- a/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build(); -} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json deleted file mode 100644 index 5fbf8a0..0000000 --- a/src-tauri/capabilities/default.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "identifier": "default", - "description": "Default permissions", - "platforms": ["windows", "linux", "macOS"], - "windows": ["main"], - "permissions": [ - "core:default", - "core:app:default", - "core:event:default", - "core:image:default", - "core:menu:default", - "core:path:default", - "core:resources:default", - "core:tray:default", - "core:webview:default", - "core:webview:allow-create-webview-window", - "core:window:default", - "core:window:allow-set-decorations", - "core:window:allow-is-fullscreen", - "core:window:allow-minimize", - "core:window:allow-toggle-maximize", - "core:window:allow-close", - "opener:default", - "gamepad:default", - "drpc:default", - "updater:default", - { - "identifier": "opener:allow-open-path", - "allow": [ - { - "path": "**" - } - ] - }, - { - "identifier": "opener:allow-reveal-item-in-dir", - "allow": [ - { - "path": "**" - } - ] - }, - "process:default", - "deep-link:default", - "core:window:allow-start-dragging" - ] -} diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json deleted file mode 100644 index d755f23..0000000 --- a/src-tauri/capabilities/desktop.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "identifier": "desktop-capability", - "platforms": ["macOS", "windows", "linux"], - "windows": ["main"], - "permissions": [ - "updater:default", - "process:default", - "deep-link:default", - "core:window:allow-start-dragging" - ] -} diff --git a/src-tauri/capabilities/mobile.json b/src-tauri/capabilities/mobile.json deleted file mode 100644 index 9ecd892..0000000 --- a/src-tauri/capabilities/mobile.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "identifier": "mobile-capability", - "description": "Mobile permissions", - "platforms": ["android", "iOS"], - "windows": ["main"], - "permissions": [ - "core:default", - "core:app:default", - "core:event:default", - "core:image:default", - "core:path:default", - "core:resources:default", - "core:webview:default", - "core:webview:allow-create-webview-window", - "core:window:default", - "opener:default", - { - "identifier": "opener:allow-open-path", - "allow": [ - { - "path": "**" - } - ] - }, - "gamepad:default", - "process:default", - "deep-link:default" - ] -} diff --git a/src-tauri/gen/android/.editorconfig b/src-tauri/gen/android/.editorconfig deleted file mode 100644 index ebe51d3..0000000 --- a/src-tauri/gen/android/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file diff --git a/src-tauri/gen/android/.gitignore b/src-tauri/gen/android/.gitignore deleted file mode 100644 index 6a893da..0000000 --- a/src-tauri/gen/android/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -.DS_Store -build -/captures -.externalNativeBuild -.cxx -local.properties -key.properties -release.keystore - -/.tauri -/tauri.settings.gradle \ No newline at end of file diff --git a/src-tauri/gen/android/app/.gitignore b/src-tauri/gen/android/app/.gitignore deleted file mode 100644 index 6c4d56b..0000000 --- a/src-tauri/gen/android/app/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/src/main/**/generated -/src/main/jniLibs/**/*.so -/src/main/assets/tauri.conf.json -/tauri.build.gradle.kts -/proguard-tauri.pro -/tauri.properties \ No newline at end of file diff --git a/src-tauri/gen/android/app/build.gradle.kts b/src-tauri/gen/android/app/build.gradle.kts deleted file mode 100644 index f44a4ea..0000000 --- a/src-tauri/gen/android/app/build.gradle.kts +++ /dev/null @@ -1,93 +0,0 @@ -import java.util.Properties - -plugins { - id("com.android.application") - id("org.jetbrains.kotlin.android") - id("rust") -} - -val tauriProperties = Properties().apply { - val propFile = file("tauri.properties") - if (propFile.exists()) { - propFile.inputStream().use { load(it) } - } -} - -val keystoreProperties = Properties().apply { - val propFile = file("key.properties") - if (propFile.exists()) { - propFile.inputStream().use { load(it) } - } -} - -android { - signingConfigs { - create("release") { - keyAlias = keystoreProperties.getProperty("keyAlias") - keyPassword = keystoreProperties.getProperty("keyPassword") - storeFile = file(keystoreProperties.getProperty("storeFile")) - storePassword = keystoreProperties.getProperty("storePassword") - } - } - compileSdk = 36 - namespace = "com.emerald.legacy" - defaultConfig { - manifestPlaceholders["usesCleartextTraffic"] = "false" - applicationId = "com.emerald.legacy" - minSdk = 26 - targetSdk = 28 - versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() - versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") - } - buildTypes { - getByName("debug") { - manifestPlaceholders["usesCleartextTraffic"] = "true" - isDebuggable = true - isJniDebuggable = true - isMinifyEnabled = false - packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") - jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") - jniLibs.keepDebugSymbols.add("*/x86/*.so") - jniLibs.keepDebugSymbols.add("*/x86_64/*.so") - } - } - getByName("release") { - signingConfig = signingConfigs.getByName("release") - isMinifyEnabled = true - proguardFiles( - *fileTree(".") { include("**/*.pro") } - .plus(getDefaultProguardFile("proguard-android-optimize.txt")) - .toList().toTypedArray() - ) - } - } - kotlinOptions { - jvmTarget = "1.8" - } - buildFeatures { - buildConfig = true - } - lint { - disable += "ExpiredTargetSdkVersion" - } - packaging { - resources.excludes += "lib/*/jni/**" - } -} - -rust { - rootDirRel = "../../../" -} - -dependencies { - implementation(project(":diamondruntime")) - implementation("androidx.webkit:webkit:1.14.0") - implementation("androidx.appcompat:appcompat:1.7.1") - implementation("androidx.activity:activity-ktx:1.10.1") - implementation("com.google.android.material:material:1.12.0") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.4") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") -} - -apply(from = "tauri.build.gradle.kts") \ No newline at end of file diff --git a/src-tauri/gen/android/app/proguard-rules.pro b/src-tauri/gen/android/app/proguard-rules.pro deleted file mode 100644 index efc3900..0000000 --- a/src-tauri/gen/android/app/proguard-rules.pro +++ /dev/null @@ -1,19 +0,0 @@ --keep class dev.lcehub.emerald.** { *; } --keepclassmembers class dev.lcehub.emerald.** { *; } --dontwarn dev.lcehub.emerald.** --keep class com.github.luben.zstd.** { *; } --keepclassmembers class com.github.luben.zstd.** { *; } --dontwarn com.github.luben.zstd.** --keep class com.emerald.legacy.TauriActivity { - public ; - public ; -} --keep class com.emerald.legacy.MainActivity { - public ; -} - --dontwarn com.android.org.conscrypt.SSLParametersImpl --dontwarn org.apache.harmony.xnet.provider.jsse.SSLParametersImpl --dontwarn org.bouncycastle.jsse.BCSSLParameters --dontwarn org.bouncycastle.jsse.BCSSLSocket --dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider diff --git a/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/src-tauri/gen/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 04986a1..0000000 --- a/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-tauri/gen/android/app/src/main/assets/resources/DLC/Emerald Skin Pack/Skins1.pck b/src-tauri/gen/android/app/src/main/assets/resources/DLC/Emerald Skin Pack/Skins1.pck deleted file mode 100644 index 3f2a5ab..0000000 Binary files a/src-tauri/gen/android/app/src/main/assets/resources/DLC/Emerald Skin Pack/Skins1.pck and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthActivity.kt b/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthActivity.kt deleted file mode 100644 index dedf68e..0000000 --- a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthActivity.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.emerald.legacy - -import android.content.Intent -import android.graphics.Bitmap -import android.net.Uri -import android.os.Bundle -import android.os.Message -import android.view.Gravity -import android.view.View -import android.view.ViewGroup -import android.webkit.WebResourceRequest -import android.webkit.WebSettings -import android.webkit.WebView -import android.webkit.WebViewClient -import android.widget.FrameLayout -import android.widget.ProgressBar -import androidx.appcompat.app.AppCompatActivity - -class LceAuthActivity : AppCompatActivity() { - private lateinit var webView: WebView - private lateinit var progressBar: ProgressBar - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val authUrl = intent.getStringExtra("authUrl") - ?: "https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher" - - progressBar = ProgressBar(this).apply { - layoutParams = FrameLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - webView = WebView(this).apply { - settings.javaScriptEnabled = true - settings.domStorageEnabled = true - settings.databaseEnabled = true - settings.loadWithOverviewMode = true - settings.useWideViewPort = true - settings.setSupportMultipleWindows(true) - settings.javaScriptCanOpenWindowsAutomatically = true - webViewClient = object : WebViewClient() { - override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean = handleAuthUrl(url) - override fun shouldOverrideUrlLoading( - view: WebView, - request: WebResourceRequest - ): Boolean = handleAuthUrl(request.url.toString()) - - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - handleAuthUrl(url) - } - - override fun onPageFinished(view: WebView, url: String) { - progressBar.visibility = View.GONE - } - } - webChromeClient = object : android.webkit.WebChromeClient() { - override fun onCreateWindow( - view: WebView, - isDialog: Boolean, - isUserGesture: Boolean, - resultMsg: Message - ): Boolean { - val transport = resultMsg.obj as WebView.WebViewTransport - transport.webView = webView - resultMsg.sendToTarget() - return true - } - } - } - - val root = FrameLayout(this) - root.addView( - webView, - FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - ) - val progressFrame = FrameLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - progressFrame.gravity = Gravity.CENTER - root.addView(progressBar, progressFrame) - setContentView(root) - webView.loadUrl(authUrl) - } - - private fun handleAuthUrl(url: String): Boolean { - val uri = try { - Uri.parse(url) - } catch (e: Exception) { - return false - } - if (uri.scheme == "emerald" && uri.host == "lceonline") { - val token = uri.getQueryParameter("token") - if (token != null) { - setResult(RESULT_OK, Intent().putExtra("lceAuthToken", token)) - } else { - setResult(RESULT_CANCELED) - } - finish() - return true - } - return false - } - - @Deprecated("Deprecated in Java") - override fun onBackPressed() { - if (webView.canGoBack()) { - webView.goBack() - } else { - setResult(RESULT_CANCELED) - super.onBackPressed() - } - } - - override fun onDestroy() { - (webView.parent as? ViewGroup)?.removeView(webView) - webView.destroy() - super.onDestroy() - } -} diff --git a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthPlugin.kt b/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthPlugin.kt deleted file mode 100644 index 04a6a27..0000000 --- a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/LceAuthPlugin.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.emerald.legacy - -import android.app.Activity -import android.content.Intent -import androidx.activity.result.ActivityResult -import app.tauri.annotation.ActivityCallback -import app.tauri.annotation.Command -import app.tauri.annotation.TauriPlugin -import app.tauri.plugin.Invoke -import app.tauri.plugin.Plugin - -@TauriPlugin -class LceAuthPlugin(private val activity: Activity) : Plugin(activity) { - @Command - fun startAuth(invoke: Invoke) { - val intent = Intent(activity, LceAuthActivity::class.java) - intent.putExtra( - "authUrl", - "https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher" - ) - startActivityForResult(invoke, intent, "authResult") - } - - @ActivityCallback - fun authResult(invoke: Invoke, result: ActivityResult) { - val token = if (result.resultCode == Activity.RESULT_OK) { - result.data?.getStringExtra("lceAuthToken") - } else { - null - } - if (!token.isNullOrEmpty()) { - invoke.resolveObject(token) - } else { - invoke.reject("Authentication cancelled or failed") - } - } -} diff --git a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/MainActivity.kt deleted file mode 100644 index 4d209a6..0000000 --- a/src-tauri/gen/android/app/src/main/java/com/emerald/legacy/MainActivity.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.emerald.legacy - -import android.os.Bundle -import android.webkit.WebView -import androidx.activity.enableEdgeToEdge -import androidx.core.view.WindowCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.WindowInsetsControllerCompat - -class MainActivity : TauriActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge() - super.onCreate(savedInstanceState) - WindowCompat.getInsetsController(window, window.decorView).apply { - systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars()) - } - } - - override fun onWebViewCreate(webView: WebView) { - super.onWebViewCreate(webView) - webView.settings.useWideViewPort = true - webView.settings.loadWithOverviewMode = true - webView.settings.setSupportZoom(false) - webView.settings.builtInZoomControls = false - webView.settings.displayZoomControls = false - } -} diff --git a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index ac3248b..0000000 --- a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml b/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 4fc2444..0000000 --- a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 8d11c83..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index b9e5600..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 05b5f00..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 3694969..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index ce13038..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index 3694969..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 43adc4c..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 0a50837..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 43adc4c..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d746596..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index a59b865..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index d746596..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4447cd9..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index e2acd39..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 4447cd9..0000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/values-night/themes.xml b/src-tauri/gen/android/app/src/main/res/values-night/themes.xml deleted file mode 100644 index 349a597..0000000 --- a/src-tauri/gen/android/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/values/colors.xml b/src-tauri/gen/android/app/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127..0000000 --- a/src-tauri/gen/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/strings.xml b/src-tauri/gen/android/app/src/main/res/values/strings.xml deleted file mode 100644 index b14475e..0000000 --- a/src-tauri/gen/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - LCE Emerald Launcher - LCE Emerald Launcher - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/themes.xml b/src-tauri/gen/android/app/src/main/res/values/themes.xml deleted file mode 100644 index 349a597..0000000 --- a/src-tauri/gen/android/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml b/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml deleted file mode 100644 index f2c4376..0000000 --- a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src-tauri/gen/android/build.gradle.kts b/src-tauri/gen/android/build.gradle.kts deleted file mode 100644 index 607240b..0000000 --- a/src-tauri/gen/android/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath("com.android.tools.build:gradle:8.11.0") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -tasks.register("clean").configure { - delete("build") -} - diff --git a/src-tauri/gen/android/buildSrc/build.gradle.kts b/src-tauri/gen/android/buildSrc/build.gradle.kts deleted file mode 100644 index 5c55bba..0000000 --- a/src-tauri/gen/android/buildSrc/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - `kotlin-dsl` -} - -gradlePlugin { - plugins { - create("pluginsForCoolKids") { - id = "rust" - implementationClass = "RustPlugin" - } - } -} - -repositories { - google() - mavenCentral() -} - -dependencies { - compileOnly(gradleApi()) - implementation("com.android.tools.build:gradle:8.11.0") -} - diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/BuildTask.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/BuildTask.kt deleted file mode 100644 index a3de125..0000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/BuildTask.kt +++ /dev/null @@ -1,68 +0,0 @@ -import java.io.File -import org.apache.tools.ant.taskdefs.condition.Os -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.logging.LogLevel -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction - -open class BuildTask : DefaultTask() { - @Input - var rootDirRel: String? = null - @Input - var target: String? = null - @Input - var release: Boolean? = null - - @TaskAction - fun assemble() { - val executable = """npm"""; - try { - runTauriCli(executable) - } catch (e: Exception) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - // Try different Windows-specific extensions - val fallbacks = listOf( - "$executable.exe", - "$executable.cmd", - "$executable.bat", - ) - - var lastException: Exception = e - for (fallback in fallbacks) { - try { - runTauriCli(fallback) - return - } catch (fallbackException: Exception) { - lastException = fallbackException - } - } - throw lastException - } else { - throw e; - } - } - } - - fun runTauriCli(executable: String) { - val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") - val target = target ?: throw GradleException("target cannot be null") - val release = release ?: throw GradleException("release cannot be null") - val args = listOf("run", "--", "tauri", "android", "android-studio-script"); - - project.exec { - workingDir(File(project.projectDir, rootDirRel)) - executable(executable) - args(args) - if (project.logger.isEnabled(LogLevel.DEBUG)) { - args("-vv") - } else if (project.logger.isEnabled(LogLevel.INFO)) { - args("-v") - } - if (release) { - args("--release") - } - args(listOf("--target", target)) - }.assertNormalExitValue() - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/RustPlugin.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/RustPlugin.kt deleted file mode 100644 index 4aa7fca..0000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/emerald/legacy/kotlin/RustPlugin.kt +++ /dev/null @@ -1,85 +0,0 @@ -import com.android.build.api.dsl.ApplicationExtension -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.get - -const val TASK_GROUP = "rust" - -open class Config { - lateinit var rootDirRel: String -} - -open class RustPlugin : Plugin { - private lateinit var config: Config - - override fun apply(project: Project) = with(project) { - config = extensions.create("rust", Config::class.java) - - val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); - val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList - - val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); - val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList - - val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") - - extensions.configure { - @Suppress("UnstableApiUsage") - flavorDimensions.add("abi") - productFlavors { - create("universal") { - dimension = "abi" - ndk { - abiFilters += abiList - } - } - defaultArchList.forEachIndexed { index, arch -> - create(arch) { - dimension = "abi" - ndk { - abiFilters.add(defaultAbiList[index]) - } - } - } - } - } - - afterEvaluate { - for (profile in listOf("debug", "release")) { - val profileCapitalized = profile.replaceFirstChar { it.uppercase() } - val buildTask = tasks.maybeCreate( - "rustBuildUniversal$profileCapitalized", - DefaultTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for all targets" - } - - tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) - - for (targetPair in targetsList.withIndex()) { - val targetName = targetPair.value - val targetArch = archList[targetPair.index] - val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } - val targetBuildTask = project.tasks.maybeCreate( - "rustBuild$targetArchCapitalized$profileCapitalized", - BuildTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for $targetArch" - rootDirRel = config.rootDirRel - target = targetName - release = profile == "release" - } - - buildTask.dependsOn(targetBuildTask) - tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( - targetBuildTask - ) - } - } - } - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/gradle.properties b/src-tauri/gen/android/gradle.properties deleted file mode 100644 index 2a7ec69..0000000 --- a/src-tauri/gen/android/gradle.properties +++ /dev/null @@ -1,24 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true -android.nonFinalResIds=false \ No newline at end of file diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index c5f9a53..0000000 --- a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue May 10 19:22:52 CST 2022 -distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip -distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME diff --git a/src-tauri/gen/android/gradlew b/src-tauri/gen/android/gradlew deleted file mode 100755 index 4f906e0..0000000 --- a/src-tauri/gen/android/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/src-tauri/gen/android/gradlew.bat b/src-tauri/gen/android/gradlew.bat deleted file mode 100644 index 107acd3..0000000 --- a/src-tauri/gen/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src-tauri/gen/android/settings.gradle b/src-tauri/gen/android/settings.gradle deleted file mode 100644 index 9006af6..0000000 --- a/src-tauri/gen/android/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -include ':app' -include ':diamondruntime' -project(':diamondruntime').projectDir = new File(settingsDir, '../../../DiamondRuntime/app/app') - -apply from: 'tauri.settings.gradle' diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json deleted file mode 100644 index f8b5943..0000000 --- a/src-tauri/gen/schemas/acl-manifests.json +++ /dev/null @@ -1 +0,0 @@ -{"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},"deep-link":{"default_permission":{"identifier":"default","description":"Allows reading the opened deep link via the get_current command","permissions":["allow-get-current"]},"permissions":{"allow-get-current":{"identifier":"allow-get-current","description":"Enables the get_current command without any pre-configured scope.","commands":{"allow":["get_current"],"deny":[]}},"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"deny-get-current":{"identifier":"deny-get-current","description":"Denies the get_current command without any pre-configured scope.","commands":{"allow":[],"deny":["get_current"]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}}},"permission_sets":{},"global_scope_schema":null},"drpc":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin","permissions":["allow-spawn-thread","allow-destroy-thread","allow-set-activity","allow-is-running"]},"permissions":{"allow-clear-activity":{"identifier":"allow-clear-activity","description":"Enables the clear_activity command without any pre-configured scope.","commands":{"allow":["clear_activity"],"deny":[]}},"allow-destroy-thread":{"identifier":"allow-destroy-thread","description":"Enables the destroy_thread command without any pre-configured scope.","commands":{"allow":["destroy_thread"],"deny":[]}},"allow-is-running":{"identifier":"allow-is-running","description":"Enables the is_running command without any pre-configured scope.","commands":{"allow":["is_running"],"deny":[]}},"allow-set-activity":{"identifier":"allow-set-activity","description":"Enables the set_activity command without any pre-configured scope.","commands":{"allow":["set_activity"],"deny":[]}},"allow-spawn-thread":{"identifier":"allow-spawn-thread","description":"Enables the spawn_thread command without any pre-configured scope.","commands":{"allow":["spawn_thread"],"deny":[]}},"deny-clear-activity":{"identifier":"deny-clear-activity","description":"Denies the clear_activity command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_activity"]}},"deny-destroy-thread":{"identifier":"deny-destroy-thread","description":"Denies the destroy_thread command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy_thread"]}},"deny-is-running":{"identifier":"deny-is-running","description":"Denies the is_running command without any pre-configured scope.","commands":{"allow":[],"deny":["is_running"]}},"deny-set-activity":{"identifier":"deny-set-activity","description":"Denies the set_activity command without any pre-configured scope.","commands":{"allow":[],"deny":["set_activity"]}},"deny-spawn-thread":{"identifier":"deny-spawn-thread","description":"Denies the spawn_thread command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn_thread"]}}},"permission_sets":{},"global_scope_schema":null},"gamepad":{"default_permission":{"identifier":"default","description":"This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n","permissions":["allow-execute"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}},"process":{"default_permission":{"identifier":"default","description":"This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n","permissions":["allow-exit","allow-restart"]},"permissions":{"allow-exit":{"identifier":"allow-exit","description":"Enables the exit command without any pre-configured scope.","commands":{"allow":["exit"],"deny":[]}},"allow-restart":{"identifier":"allow-restart","description":"Enables the restart command without any pre-configured scope.","commands":{"allow":["restart"],"deny":[]}},"deny-exit":{"identifier":"deny-exit","description":"Denies the exit command without any pre-configured scope.","commands":{"allow":[],"deny":["exit"]}},"deny-restart":{"identifier":"deny-restart","description":"Denies the restart command without any pre-configured scope.","commands":{"allow":[],"deny":["restart"]}}},"permission_sets":{},"global_scope_schema":null},"updater":{"default_permission":{"identifier":"default","description":"This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n","permissions":["allow-check","allow-download","allow-install","allow-download-and-install"]},"permissions":{"allow-check":{"identifier":"allow-check","description":"Enables the check command without any pre-configured scope.","commands":{"allow":["check"],"deny":[]}},"allow-download":{"identifier":"allow-download","description":"Enables the download command without any pre-configured scope.","commands":{"allow":["download"],"deny":[]}},"allow-download-and-install":{"identifier":"allow-download-and-install","description":"Enables the download_and_install command without any pre-configured scope.","commands":{"allow":["download_and_install"],"deny":[]}},"allow-install":{"identifier":"allow-install","description":"Enables the install command without any pre-configured scope.","commands":{"allow":["install"],"deny":[]}},"deny-check":{"identifier":"deny-check","description":"Denies the check command without any pre-configured scope.","commands":{"allow":[],"deny":["check"]}},"deny-download":{"identifier":"deny-download","description":"Denies the download command without any pre-configured scope.","commands":{"allow":[],"deny":["download"]}},"deny-download-and-install":{"identifier":"deny-download-and-install","description":"Denies the download_and_install command without any pre-configured scope.","commands":{"allow":[],"deny":["download_and_install"]}},"deny-install":{"identifier":"deny-install","description":"Denies the install command without any pre-configured scope.","commands":{"allow":[],"deny":["install"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json deleted file mode 100644 index f43cc28..0000000 --- a/src-tauri/gen/schemas/capabilities.json +++ /dev/null @@ -1 +0,0 @@ -{"default":{"identifier":"default","description":"Default permissions","local":true,"windows":["main"],"permissions":["core:default","core:app:default","core:event:default","core:image:default","core:menu:default","core:path:default","core:resources:default","core:tray:default","core:webview:default","core:webview:allow-create-webview-window","core:window:default","core:window:allow-set-decorations","core:window:allow-is-fullscreen","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-close","opener:default","gamepad:default","drpc:default","updater:default",{"identifier":"opener:allow-open-path","allow":[{"path":"**"}]},{"identifier":"opener:allow-reveal-item-in-dir","allow":[{"path":"**"}]},"process:default","deep-link:default","core:window:allow-start-dragging"],"platforms":["windows","linux","macOS"]},"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["updater:default","process:default","deep-link:default","core:window:allow-start-dragging"],"platforms":["macOS","windows","linux"]},"mobile-capability":{"identifier":"mobile-capability","description":"Mobile permissions","local":true,"windows":["main"],"permissions":["core:default","core:app:default","core:event:default","core:image:default","core:path:default","core:resources:default","core:webview:default","core:webview:allow-create-webview-window","core:window:default","opener:default",{"identifier":"opener:allow-open-path","allow":[{"path":"**"}]},"gamepad:default","process:default","deep-link:default"],"platforms":["android","iOS"]}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/desktop-schema.json b/src-tauri/gen/schemas/desktop-schema.json deleted file mode 100644 index 2d3bcc0..0000000 --- a/src-tauri/gen/schemas/desktop-schema.json +++ /dev/null @@ -1,2699 +0,0 @@ -{ - "$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": [ - { - "if": { - "properties": { - "identifier": { - "anyOf": [ - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." - } - ] - } - } - }, - "then": { - "properties": { - "allow": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - }, - "deny": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - } - } - }, - "properties": { - "identifier": { - "description": "Identifier of the permission or permission set.", - "allOf": [ - { - "$ref": "#/definitions/Identifier" - } - ] - } - } - }, - { - "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": "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": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`", - "type": "string", - "const": "deep-link:default", - "markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`" - }, - { - "description": "Enables the get_current command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-get-current", - "markdownDescription": "Enables the get_current command without any pre-configured scope." - }, - { - "description": "Enables the is_registered command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-is-registered", - "markdownDescription": "Enables the is_registered command without any pre-configured scope." - }, - { - "description": "Enables the register command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-register", - "markdownDescription": "Enables the register command without any pre-configured scope." - }, - { - "description": "Enables the unregister command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-unregister", - "markdownDescription": "Enables the unregister command without any pre-configured scope." - }, - { - "description": "Denies the get_current command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-get-current", - "markdownDescription": "Denies the get_current command without any pre-configured scope." - }, - { - "description": "Denies the is_registered command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-is-registered", - "markdownDescription": "Denies the is_registered command without any pre-configured scope." - }, - { - "description": "Denies the register command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-register", - "markdownDescription": "Denies the register command without any pre-configured scope." - }, - { - "description": "Denies the unregister command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-unregister", - "markdownDescription": "Denies the unregister command without any pre-configured scope." - }, - { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`", - "type": "string", - "const": "drpc:default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`" - }, - { - "description": "Enables the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-clear-activity", - "markdownDescription": "Enables the clear_activity command without any pre-configured scope." - }, - { - "description": "Enables the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-destroy-thread", - "markdownDescription": "Enables the destroy_thread command without any pre-configured scope." - }, - { - "description": "Enables the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-is-running", - "markdownDescription": "Enables the is_running command without any pre-configured scope." - }, - { - "description": "Enables the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-set-activity", - "markdownDescription": "Enables the set_activity command without any pre-configured scope." - }, - { - "description": "Enables the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-spawn-thread", - "markdownDescription": "Enables the spawn_thread command without any pre-configured scope." - }, - { - "description": "Denies the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-clear-activity", - "markdownDescription": "Denies the clear_activity command without any pre-configured scope." - }, - { - "description": "Denies the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-destroy-thread", - "markdownDescription": "Denies the destroy_thread command without any pre-configured scope." - }, - { - "description": "Denies the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-is-running", - "markdownDescription": "Denies the is_running command without any pre-configured scope." - }, - { - "description": "Denies the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-set-activity", - "markdownDescription": "Denies the set_activity command without any pre-configured scope." - }, - { - "description": "Denies the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-spawn-thread", - "markdownDescription": "Denies the spawn_thread command without any pre-configured scope." - }, - { - "description": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`", - "type": "string", - "const": "gamepad:default", - "markdownDescription": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`" - }, - { - "description": "Enables the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:allow-execute", - "markdownDescription": "Enables the execute command without any pre-configured scope." - }, - { - "description": "Denies the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:deny-execute", - "markdownDescription": "Denies the execute command without any pre-configured scope." - }, - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n\n#### This default permission set includes:\n\n- `allow-exit`\n- `allow-restart`", - "type": "string", - "const": "process:default", - "markdownDescription": "This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n\n#### This default permission set includes:\n\n- `allow-exit`\n- `allow-restart`" - }, - { - "description": "Enables the exit command without any pre-configured scope.", - "type": "string", - "const": "process:allow-exit", - "markdownDescription": "Enables the exit command without any pre-configured scope." - }, - { - "description": "Enables the restart command without any pre-configured scope.", - "type": "string", - "const": "process:allow-restart", - "markdownDescription": "Enables the restart command without any pre-configured scope." - }, - { - "description": "Denies the exit command without any pre-configured scope.", - "type": "string", - "const": "process:deny-exit", - "markdownDescription": "Denies the exit command without any pre-configured scope." - }, - { - "description": "Denies the restart command without any pre-configured scope.", - "type": "string", - "const": "process:deny-restart", - "markdownDescription": "Denies the restart command without any pre-configured scope." - }, - { - "description": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`", - "type": "string", - "const": "updater:default", - "markdownDescription": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`" - }, - { - "description": "Enables the check command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-check", - "markdownDescription": "Enables the check command without any pre-configured scope." - }, - { - "description": "Enables the download command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-download", - "markdownDescription": "Enables the download command without any pre-configured scope." - }, - { - "description": "Enables the download_and_install command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-download-and-install", - "markdownDescription": "Enables the download_and_install command without any pre-configured scope." - }, - { - "description": "Enables the install command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-install", - "markdownDescription": "Enables the install command without any pre-configured scope." - }, - { - "description": "Denies the check command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-check", - "markdownDescription": "Denies the check command without any pre-configured scope." - }, - { - "description": "Denies the download command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-download", - "markdownDescription": "Denies the download command without any pre-configured scope." - }, - { - "description": "Denies the download_and_install command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-download-and-install", - "markdownDescription": "Denies the download_and_install command without any pre-configured scope." - }, - { - "description": "Denies the install command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-install", - "markdownDescription": "Denies the install 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" - ] - } - ] - }, - "Application": { - "description": "Opener scope application.", - "anyOf": [ - { - "description": "Open in default application.", - "type": "null" - }, - { - "description": "If true, allow open with any application.", - "type": "boolean" - }, - { - "description": "Allow specific application to open with.", - "type": "string" - } - ] - } - } -} \ No newline at end of file diff --git a/src-tauri/gen/schemas/linux-schema.json b/src-tauri/gen/schemas/linux-schema.json deleted file mode 100644 index 2d3bcc0..0000000 --- a/src-tauri/gen/schemas/linux-schema.json +++ /dev/null @@ -1,2699 +0,0 @@ -{ - "$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": [ - { - "if": { - "properties": { - "identifier": { - "anyOf": [ - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." - } - ] - } - } - }, - "then": { - "properties": { - "allow": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - }, - "deny": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - } - } - }, - "properties": { - "identifier": { - "description": "Identifier of the permission or permission set.", - "allOf": [ - { - "$ref": "#/definitions/Identifier" - } - ] - } - } - }, - { - "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": "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": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`", - "type": "string", - "const": "deep-link:default", - "markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`" - }, - { - "description": "Enables the get_current command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-get-current", - "markdownDescription": "Enables the get_current command without any pre-configured scope." - }, - { - "description": "Enables the is_registered command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-is-registered", - "markdownDescription": "Enables the is_registered command without any pre-configured scope." - }, - { - "description": "Enables the register command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-register", - "markdownDescription": "Enables the register command without any pre-configured scope." - }, - { - "description": "Enables the unregister command without any pre-configured scope.", - "type": "string", - "const": "deep-link:allow-unregister", - "markdownDescription": "Enables the unregister command without any pre-configured scope." - }, - { - "description": "Denies the get_current command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-get-current", - "markdownDescription": "Denies the get_current command without any pre-configured scope." - }, - { - "description": "Denies the is_registered command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-is-registered", - "markdownDescription": "Denies the is_registered command without any pre-configured scope." - }, - { - "description": "Denies the register command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-register", - "markdownDescription": "Denies the register command without any pre-configured scope." - }, - { - "description": "Denies the unregister command without any pre-configured scope.", - "type": "string", - "const": "deep-link:deny-unregister", - "markdownDescription": "Denies the unregister command without any pre-configured scope." - }, - { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`", - "type": "string", - "const": "drpc:default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`" - }, - { - "description": "Enables the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-clear-activity", - "markdownDescription": "Enables the clear_activity command without any pre-configured scope." - }, - { - "description": "Enables the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-destroy-thread", - "markdownDescription": "Enables the destroy_thread command without any pre-configured scope." - }, - { - "description": "Enables the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-is-running", - "markdownDescription": "Enables the is_running command without any pre-configured scope." - }, - { - "description": "Enables the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-set-activity", - "markdownDescription": "Enables the set_activity command without any pre-configured scope." - }, - { - "description": "Enables the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-spawn-thread", - "markdownDescription": "Enables the spawn_thread command without any pre-configured scope." - }, - { - "description": "Denies the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-clear-activity", - "markdownDescription": "Denies the clear_activity command without any pre-configured scope." - }, - { - "description": "Denies the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-destroy-thread", - "markdownDescription": "Denies the destroy_thread command without any pre-configured scope." - }, - { - "description": "Denies the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-is-running", - "markdownDescription": "Denies the is_running command without any pre-configured scope." - }, - { - "description": "Denies the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-set-activity", - "markdownDescription": "Denies the set_activity command without any pre-configured scope." - }, - { - "description": "Denies the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-spawn-thread", - "markdownDescription": "Denies the spawn_thread command without any pre-configured scope." - }, - { - "description": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`", - "type": "string", - "const": "gamepad:default", - "markdownDescription": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`" - }, - { - "description": "Enables the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:allow-execute", - "markdownDescription": "Enables the execute command without any pre-configured scope." - }, - { - "description": "Denies the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:deny-execute", - "markdownDescription": "Denies the execute command without any pre-configured scope." - }, - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n\n#### This default permission set includes:\n\n- `allow-exit`\n- `allow-restart`", - "type": "string", - "const": "process:default", - "markdownDescription": "This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n\n#### This default permission set includes:\n\n- `allow-exit`\n- `allow-restart`" - }, - { - "description": "Enables the exit command without any pre-configured scope.", - "type": "string", - "const": "process:allow-exit", - "markdownDescription": "Enables the exit command without any pre-configured scope." - }, - { - "description": "Enables the restart command without any pre-configured scope.", - "type": "string", - "const": "process:allow-restart", - "markdownDescription": "Enables the restart command without any pre-configured scope." - }, - { - "description": "Denies the exit command without any pre-configured scope.", - "type": "string", - "const": "process:deny-exit", - "markdownDescription": "Denies the exit command without any pre-configured scope." - }, - { - "description": "Denies the restart command without any pre-configured scope.", - "type": "string", - "const": "process:deny-restart", - "markdownDescription": "Denies the restart command without any pre-configured scope." - }, - { - "description": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`", - "type": "string", - "const": "updater:default", - "markdownDescription": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`" - }, - { - "description": "Enables the check command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-check", - "markdownDescription": "Enables the check command without any pre-configured scope." - }, - { - "description": "Enables the download command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-download", - "markdownDescription": "Enables the download command without any pre-configured scope." - }, - { - "description": "Enables the download_and_install command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-download-and-install", - "markdownDescription": "Enables the download_and_install command without any pre-configured scope." - }, - { - "description": "Enables the install command without any pre-configured scope.", - "type": "string", - "const": "updater:allow-install", - "markdownDescription": "Enables the install command without any pre-configured scope." - }, - { - "description": "Denies the check command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-check", - "markdownDescription": "Denies the check command without any pre-configured scope." - }, - { - "description": "Denies the download command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-download", - "markdownDescription": "Denies the download command without any pre-configured scope." - }, - { - "description": "Denies the download_and_install command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-download-and-install", - "markdownDescription": "Denies the download_and_install command without any pre-configured scope." - }, - { - "description": "Denies the install command without any pre-configured scope.", - "type": "string", - "const": "updater:deny-install", - "markdownDescription": "Denies the install 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" - ] - } - ] - }, - "Application": { - "description": "Opener scope application.", - "anyOf": [ - { - "description": "Open in default application.", - "type": "null" - }, - { - "description": "If true, allow open with any application.", - "type": "boolean" - }, - { - "description": "Allow specific application to open with.", - "type": "string" - } - ] - } - } -} \ No newline at end of file diff --git a/src-tauri/gen/schemas/windows-schema.json b/src-tauri/gen/schemas/windows-schema.json deleted file mode 100644 index 56eb6a8..0000000 --- a/src-tauri/gen/schemas/windows-schema.json +++ /dev/null @@ -1,2561 +0,0 @@ -{ - "$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": [ - { - "if": { - "properties": { - "identifier": { - "anyOf": [ - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." - } - ] - } - } - }, - "then": { - "properties": { - "allow": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - }, - "deny": { - "items": { - "title": "OpenerScopeEntry", - "description": "Opener scope entry.", - "anyOf": [ - { - "type": "object", - "required": [ - "url" - ], - "properties": { - "app": { - "description": "An application to open this url with, for example: firefox.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "url": { - "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "path" - ], - "properties": { - "app": { - "description": "An application to open this path with, for example: xdg-open.", - "allOf": [ - { - "$ref": "#/definitions/Application" - } - ] - }, - "path": { - "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", - "type": "string" - } - } - } - ] - } - } - } - }, - "properties": { - "identifier": { - "description": "Identifier of the permission or permission set.", - "allOf": [ - { - "$ref": "#/definitions/Identifier" - } - ] - } - } - }, - { - "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": "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": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`", - "type": "string", - "const": "drpc:default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-spawn-thread`\n- `allow-destroy-thread`\n- `allow-set-activity`\n- `allow-is-running`" - }, - { - "description": "Enables the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-clear-activity", - "markdownDescription": "Enables the clear_activity command without any pre-configured scope." - }, - { - "description": "Enables the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-destroy-thread", - "markdownDescription": "Enables the destroy_thread command without any pre-configured scope." - }, - { - "description": "Enables the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-is-running", - "markdownDescription": "Enables the is_running command without any pre-configured scope." - }, - { - "description": "Enables the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-set-activity", - "markdownDescription": "Enables the set_activity command without any pre-configured scope." - }, - { - "description": "Enables the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:allow-spawn-thread", - "markdownDescription": "Enables the spawn_thread command without any pre-configured scope." - }, - { - "description": "Denies the clear_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-clear-activity", - "markdownDescription": "Denies the clear_activity command without any pre-configured scope." - }, - { - "description": "Denies the destroy_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-destroy-thread", - "markdownDescription": "Denies the destroy_thread command without any pre-configured scope." - }, - { - "description": "Denies the is_running command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-is-running", - "markdownDescription": "Denies the is_running command without any pre-configured scope." - }, - { - "description": "Denies the set_activity command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-set-activity", - "markdownDescription": "Denies the set_activity command without any pre-configured scope." - }, - { - "description": "Denies the spawn_thread command without any pre-configured scope.", - "type": "string", - "const": "drpc:deny-spawn-thread", - "markdownDescription": "Denies the spawn_thread command without any pre-configured scope." - }, - { - "description": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`", - "type": "string", - "const": "gamepad:default", - "markdownDescription": "This permission set configures which\ngampead features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all gamepads.\n\n\n#### This default permission set includes:\n\n- `allow-execute`" - }, - { - "description": "Enables the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:allow-execute", - "markdownDescription": "Enables the execute command without any pre-configured scope." - }, - { - "description": "Denies the execute command without any pre-configured scope.", - "type": "string", - "const": "gamepad:deny-execute", - "markdownDescription": "Denies the execute command without any pre-configured scope." - }, - { - "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", - "type": "string", - "const": "opener:default", - "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" - }, - { - "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", - "type": "string", - "const": "opener:allow-default-urls", - "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." - }, - { - "description": "Enables the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-path", - "markdownDescription": "Enables the open_path command without any pre-configured scope." - }, - { - "description": "Enables the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-open-url", - "markdownDescription": "Enables the open_url command without any pre-configured scope." - }, - { - "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:allow-reveal-item-in-dir", - "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." - }, - { - "description": "Denies the open_path command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-path", - "markdownDescription": "Denies the open_path command without any pre-configured scope." - }, - { - "description": "Denies the open_url command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-open-url", - "markdownDescription": "Denies the open_url command without any pre-configured scope." - }, - { - "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", - "type": "string", - "const": "opener:deny-reveal-item-in-dir", - "markdownDescription": "Denies the reveal_item_in_dir 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" - ] - } - ] - }, - "Application": { - "description": "Opener scope application.", - "anyOf": [ - { - "description": "Open in default application.", - "type": "null" - }, - { - "description": "If true, allow open with any application.", - "type": "boolean" - }, - { - "description": "Allow specific application to open with.", - "type": "string" - } - ] - } - } -} \ No newline at end of file diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png deleted file mode 100644 index fe90450..0000000 Binary files a/src-tauri/icons/128x128.png and /dev/null differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png deleted file mode 100644 index 646bb0b..0000000 Binary files a/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png deleted file mode 100644 index ed80aaf..0000000 Binary files a/src-tauri/icons/32x32.png and /dev/null differ diff --git a/src-tauri/icons/64x64.png b/src-tauri/icons/64x64.png deleted file mode 100644 index 61491c5..0000000 Binary files a/src-tauri/icons/64x64.png and /dev/null differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png deleted file mode 100644 index 4ae0aab..0000000 Binary files a/src-tauri/icons/Square107x107Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png deleted file mode 100644 index 78c31fa..0000000 Binary files a/src-tauri/icons/Square142x142Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png deleted file mode 100644 index c6d9078..0000000 Binary files a/src-tauri/icons/Square150x150Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png deleted file mode 100644 index 7529ace..0000000 Binary files a/src-tauri/icons/Square284x284Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png deleted file mode 100644 index a53ee17..0000000 Binary files a/src-tauri/icons/Square30x30Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png deleted file mode 100644 index bbe10da..0000000 Binary files a/src-tauri/icons/Square310x310Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png deleted file mode 100644 index 6c61d34..0000000 Binary files a/src-tauri/icons/Square44x44Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png deleted file mode 100644 index ea5e4d7..0000000 Binary files a/src-tauri/icons/Square71x71Logo.png and /dev/null differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png deleted file mode 100644 index 097d01d..0000000 Binary files a/src-tauri/icons/Square89x89Logo.png and /dev/null differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png deleted file mode 100644 index e21d4f3..0000000 Binary files a/src-tauri/icons/StoreLogo.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml b/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 2ffbf24..0000000 --- a/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a15abdb..0000000 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index bd1155a..0000000 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index a9dcd30..0000000 Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 6970c76..0000000 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 1138cb0..0000000 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index e0c477b..0000000 Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index d97dd86..0000000 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 4fe9217..0000000 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 8c4b277..0000000 Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index db27ed1..0000000 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index caef101..0000000 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index b0d63c9..0000000 Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index e465f15..0000000 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 55c9a1d..0000000 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 4295cea..0000000 Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/icons/android/values/ic_launcher_background.xml b/src-tauri/icons/android/values/ic_launcher_background.xml deleted file mode 100644 index ea9c223..0000000 --- a/src-tauri/icons/android/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #fff - \ No newline at end of file diff --git a/src-tauri/icons/app-icon.png b/src-tauri/icons/app-icon.png deleted file mode 100644 index c0b444d..0000000 Binary files a/src-tauri/icons/app-icon.png and /dev/null differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns deleted file mode 100644 index 424714b..0000000 Binary files a/src-tauri/icons/icon.icns and /dev/null differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico deleted file mode 100644 index 7ed101a..0000000 Binary files a/src-tauri/icons/icon.ico and /dev/null differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png deleted file mode 100644 index 58f663d..0000000 Binary files a/src-tauri/icons/icon.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png deleted file mode 100644 index 50a45b7..0000000 Binary files a/src-tauri/icons/ios/AppIcon-20x20@1x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png deleted file mode 100644 index 2ad830b..0000000 Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png deleted file mode 100644 index 2ad830b..0000000 Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png deleted file mode 100644 index b5d9796..0000000 Binary files a/src-tauri/icons/ios/AppIcon-20x20@3x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@1x.png b/src-tauri/icons/ios/AppIcon-29x29@1x.png deleted file mode 100644 index 1f5ec6e..0000000 Binary files a/src-tauri/icons/ios/AppIcon-29x29@1x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png deleted file mode 100644 index bc5eb17..0000000 Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x.png b/src-tauri/icons/ios/AppIcon-29x29@2x.png deleted file mode 100644 index bc5eb17..0000000 Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@3x.png b/src-tauri/icons/ios/AppIcon-29x29@3x.png deleted file mode 100644 index 5e7b50e..0000000 Binary files a/src-tauri/icons/ios/AppIcon-29x29@3x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png deleted file mode 100644 index 2ad830b..0000000 Binary files a/src-tauri/icons/ios/AppIcon-40x40@1x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png deleted file mode 100644 index 78ba875..0000000 Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x.png b/src-tauri/icons/ios/AppIcon-40x40@2x.png deleted file mode 100644 index 78ba875..0000000 Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@3x.png b/src-tauri/icons/ios/AppIcon-40x40@3x.png deleted file mode 100644 index 9093650..0000000 Binary files a/src-tauri/icons/ios/AppIcon-40x40@3x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png deleted file mode 100644 index a3c35e1..0000000 Binary files a/src-tauri/icons/ios/AppIcon-512@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@2x.png b/src-tauri/icons/ios/AppIcon-60x60@2x.png deleted file mode 100644 index 9093650..0000000 Binary files a/src-tauri/icons/ios/AppIcon-60x60@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png deleted file mode 100644 index b69f231..0000000 Binary files a/src-tauri/icons/ios/AppIcon-60x60@3x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png deleted file mode 100644 index 56c029b..0000000 Binary files a/src-tauri/icons/ios/AppIcon-76x76@1x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@2x.png b/src-tauri/icons/ios/AppIcon-76x76@2x.png deleted file mode 100644 index 2bd3a22..0000000 Binary files a/src-tauri/icons/ios/AppIcon-76x76@2x.png and /dev/null differ diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png deleted file mode 100644 index 23d62da..0000000 Binary files a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and /dev/null differ diff --git a/src-tauri/scripts/post-build-macos.sh b/src-tauri/scripts/post-build-macos.sh deleted file mode 100755 index 02d995e..0000000 --- a/src-tauri/scripts/post-build-macos.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# Post-build script for macOS to fix quarantine issues (thank u apple...) -# This script runs automatically after Tauri build on macOS - -set -e - -if [ "$(uname)" != "Darwin" ]; then - echo "Not macOS, skipping post-build fixes" - exit 0 -fi - -APP_NAME="Emerald Legacy Launcher" -BUNDLE_ID="com.emerald.legacy" -BASE_DIR="src-tauri/target" - -echo "Running macOS post-build fixes" - -# Find the correct target directory (handles both native and cross-compilation) -TARGET_DIR=$(find "$BASE_DIR" -path "*/release/bundle/macos" -type d | head -n 1) - -if [ -z "$TARGET_DIR" ]; then - echo "❌ No macOS bundle directory found in $BASE_DIR" - exit 1 -fi - -echo "Using target directory: $TARGET_DIR" - -APP_PATH=$(find "$TARGET_DIR" -name "*.app" -type d | head -n 1) - -if [ -z "$APP_PATH" ]; then - echo "❌ No .app bundle found in $TARGET_DIR" - exit 1 -fi - -echo "Found app: $APP_PATH" - -echo "Removing quarantine attributes..." -xattr -cr "$APP_PATH" - -echo "Applying ad-hoc signature..." -codesign --force --deep --sign - "$APP_PATH" 2>/dev/null || { - echo "⚠️ Code signing failed, but quarantine removal should work" -} - -echo "Verifying app signature..." -codesign -v "$APP_PATH" 2>/dev/null && echo "✅ App signature verified" || echo "⚠️ App signature verification failed" - -echo "✅ macOS post-build fixes completed!" -echo "The app should now launch without 'damaged' error on macOS ARM" diff --git a/src-tauri/src/android_runtime.rs b/src-tauri/src/android_runtime.rs deleted file mode 100644 index ffe0ee9..0000000 --- a/src-tauri/src/android_runtime.rs +++ /dev/null @@ -1,104 +0,0 @@ -pub enum BridgeAction { - Play, - OpenContainer, - OpenSettings, - SwitchProton, - InstallDriver, - SetAudioBackend, -} - -pub fn launch_bridge( - instance_path: String, - action: BridgeAction, - extra_args: Vec, -) -> Result<(), String> { - #[cfg(target_os = "android")] - { - use jni::objects::{JObject, JValue}; - use jni::sys::jint; - use jni::JNIEnv; - use wry::prelude::{dispatch, find_class}; - fn start_bridge( - env: &mut JNIEnv, - activity: &JObject, - action: &str, - instance_path: &str, - extra_args: &[String], - ) -> jni::errors::Result<()> { - let bridge_class = - find_class(env, activity, "dev.lcehub.emerald.LauncherBridgeActivity".to_string())?; - let intent_class = env.find_class("android/content/Intent")?; - let intent = env.new_object( - intent_class, - "(Landroid/content/Context;Ljava/lang/Class;)V", //neo: i hate smali so much - &[(&activity).into(), (&bridge_class).into()], - )?; - - let extra_action = env.new_string("launcher_action")?; - let action_str = env.new_string(action)?; - env.call_method( - &intent, - "putExtra", - "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", - &[(&extra_action).into(), (&action_str).into()], - )?; - - let extra_path = env.new_string("instance_path")?; - let path_str = env.new_string(instance_path)?; - env.call_method( - &intent, - "putExtra", - "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", - &[(&extra_path).into(), (&path_str).into()], - )?; - - let extra_args_key = env.new_string("extra_args")?; - let extra_args_json = - env.new_string(&serde_json::to_string(extra_args).unwrap_or_else(|_| "[]".into()))?; - env.call_method( - &intent, - "putExtra", - "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", - &[(&extra_args_key).into(), (&extra_args_json).into()], - )?; - - env.call_method( - &intent, - "addFlags", - "(I)Landroid/content/Intent;", - &[JValue::Int(0x10000000 as jint)], //neo: FLAG_ACTIVITY_NEW_TASK - )?; - - env.call_method( - activity, - "startActivity", - "(Landroid/content/Intent;)V", - &[(&intent).into()], - )?; - - Ok(()) - } - - let action_str = match action { - BridgeAction::Play => "play", - BridgeAction::OpenContainer => "open", - BridgeAction::OpenSettings => "settings", - BridgeAction::SwitchProton => "switch_proton", - BridgeAction::InstallDriver => "install_driver", - BridgeAction::SetAudioBackend => "set_audio_backend", - } - .to_string(); - dispatch(move |env, activity, _webview| { - if let Err(e) = start_bridge(env, activity, &action_str, &instance_path, &extra_args) { - eprintln!("[android_bridge] failed to start activity: {e}"); - } - }); - - Ok(()) - } - #[cfg(not(target_os = "android"))] - { - let _ = (instance_path, action, extra_args); - Err("Only supported on Android".into()) - } -} diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs deleted file mode 100644 index 327508f..0000000 --- a/src-tauri/src/commands/config.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::fs; -use tauri::AppHandle; -use crate::config; -use crate::types::{AppConfig, ThemePalette}; -use crate::util; -#[tauri::command] -pub fn save_config(app: AppHandle, config_val: AppConfig) { - let mut config_val = config_val; - if config_val.goldmapper_mappings.is_none() { - let existing = config::load_config_raw(app.clone()); - config_val.goldmapper_mappings = existing.goldmapper_mappings; - } - config::save_config_raw(&app, &config_val); -} - -#[tauri::command] -pub fn load_config(app: AppHandle) -> AppConfig { - config::load_config_raw(app) -} - -#[tauri::command] -pub fn get_external_palettes(app: AppHandle) -> Vec { - let themes_dir = util::get_app_dir(&app).join("themes"); - let _ = fs::create_dir_all(&themes_dir); - let mut palettes = Vec::new(); - if let Ok(entries) = fs::read_dir(themes_dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.extension().and_then(|s| s.to_str()) == Some("json") { - if let Ok(content) = fs::read_to_string(&path) { - if let Ok(palette) = serde_json::from_str::(&content) { - palettes.push(palette); - } - } - } - } - } - palettes -} - -#[cfg(desktop)] -#[tauri::command] -pub fn import_theme(app: AppHandle) -> Result { - let file = rfd::FileDialog::new() - .add_filter("JSON Theme", &["json"]) - .set_title("Import Theme Palette") - .pick_file(); - - if let Some(src_path) = file { - let content = fs::read_to_string(&src_path).map_err(|e| e.to_string())?; - let palette: ThemePalette = - serde_json::from_str(&content).map_err(|_| "Invalid theme JSON format".to_string())?; - let themes_dir = util::get_app_dir(&app).join("themes"); - let _ = fs::create_dir_all(&themes_dir); - let dest_path = themes_dir.join(format!("{}.json", palette.id)); - fs::write(dest_path, content).map_err(|e| e.to_string())?; - Ok(palette.name) - } else { - Err("CANCELED".into()) - } -} - -#[cfg(desktop)] -#[tauri::command] -pub fn export_settings(app: AppHandle) -> Result<(), String> { - let config = config::load_config_raw(app.clone()); - let json = serde_json::to_string_pretty(&config).map_err(|e| e.to_string())?; - let file = rfd::FileDialog::new() - .add_filter("Emerald Settings", &["json"]) - .set_title("Export Launcher Settings") - .set_file_name("emerald_settings.json") - .save_file(); - - if let Some(path) = file { - fs::write(&path, &json).map_err(|e| e.to_string())?; - Ok(()) - } else { - Err("CANCELED".into()) - } -} - -#[cfg(desktop)] -#[tauri::command] -pub fn import_settings(app: AppHandle) -> Result { - let file = rfd::FileDialog::new() - .add_filter("Emerald Settings", &["json"]) - .set_title("Import Launcher Settings") - .pick_file(); - - if let Some(path) = file { - let content = fs::read_to_string(&path).map_err(|e| e.to_string())?; - let config: AppConfig = - serde_json::from_str(&content).map_err(|_| "Invalid settings JSON format".to_string())?; - config::save_config_raw(&app, &config); - Ok("Settings imported successfully! Restart the launcher to apply.".into()) - } else { - Err("CANCELED".into()) - } -} diff --git a/src-tauri/src/commands/console2lce.rs b/src-tauri/src/commands/console2lce.rs deleted file mode 100644 index 493e714..0000000 --- a/src-tauri/src/commands/console2lce.rs +++ /dev/null @@ -1,1209 +0,0 @@ -use std::collections::HashMap; -use std::collections::HashSet; -use std::fs; -use std::io::{Read, Write}; -use std::path::Path; -use tauri::AppHandle; -const STFS_MAGIC: [u8; 4] = *b"CON "; -const STFS_BASE_OFFSET: usize = 0xA000; -const STFS_BLOCK_SIZE: usize = 0x1000; -const STFS_BLOCKS_PER_GRP: usize = 170; -const FILE_ENTRY_SIZE: usize = 144; -const REGION_SECT_COUNT: usize = 1024; -const LZX_BLOCK_SIZE: usize = 0x8000; -const SFO_FMT_UTF8_RAW: u16 = 0x0004; -const SFO_FMT_UTF8_STR: u16 = 0x0204; -const SFO_FMT_INT32: u16 = 0x0404; -const LEVELNAME_SIG: &[u8] = b"\x08\x00\x09LevelName"; -const PLAYER_POS_SIG: &[u8] = b"\x09\x00\x03Pos\x06\x00\x00\x00\x03"; -struct StfsEntry { - name: String, - start_block: usize, - size: usize, -} - -struct FileEntry { - filename: String, - length: u32, - start_offset: u32, - last_mod: i64, -} - -fn s32(buf: &mut [u8], o: usize) { - buf[o..o + 4].reverse(); -} - -fn read_hdr_be(data: &[u8]) -> (u32, u32, i16, i16) { - let ho = u32::from_be_bytes([data[0], data[1], data[2], data[3]]); - let ne = u32::from_be_bytes([data[4], data[5], data[6], data[7]]); - let ov = i16::from_be_bytes([data[8], data[9]]); - let cv = i16::from_be_bytes([data[10], data[11]]); - (ho, ne, ov, cv) -} - -fn parse_ftable_be(data: &[u8], ho: u32, ne: u32) -> Vec { - let mut out = Vec::new(); - for i in 0..ne { - let base = ho as usize + i as usize * FILE_ENTRY_SIZE; - if base + FILE_ENTRY_SIZE > data.len() { - break; - } - let raw = &data[base..base + FILE_ENTRY_SIZE]; - let fn_u16s: Vec = (0..64) - .map(|j| u16::from_be_bytes([raw[j * 2], raw[j * 2 + 1]])) - .collect(); - let fn_str: String = fn_u16s - .iter() - .take_while(|&&c| c != 0) - .filter_map(|&c| char::from_u32(c as u32)) - .collect(); - let length = u32::from_be_bytes([raw[128], raw[129], raw[130], raw[131]]); - let start_offset = u32::from_be_bytes([raw[132], raw[133], raw[134], raw[135]]); - let last_mod = i64::from_be_bytes([ - raw[136], raw[137], raw[138], raw[139], raw[140], raw[141], raw[142], raw[143], - ]); - if !fn_str.is_empty() && length > 0 { - out.push(FileEntry { - filename: fn_str, - length, - start_offset, - last_mod, - }); - } - } - out -} - -fn sanitise(name: &str) -> String { - let mut s = String::new(); - let mut prev_underscore = false; - for c in name.chars() { - let replace = c.is_control() - || matches!( - c, - '<' | '>' | ':' | '"' | '/' | '\\' | '|' | '?' | '*' - ); - let c = if replace { '_' } else { c }; - if c == '_' { - if !prev_underscore { - s.push(c); - } - prev_underscore = true; - } else { - s.push(c); - prev_underscore = false; - } - } - let s = s.trim_matches(|c: char| c == '_' || c == '.' || c == ' '); - let s = if s.len() > 64 { &s[..64] } else { s }; - if s.is_empty() { - "MinecraftSave".to_string() - } else { - s.to_string() - } -} - -fn stfs_block_offset(block_num: usize, table_shift: usize) -> usize { - let g = block_num / STFS_BLOCKS_PER_GRP; - let hash_before = if g == 0 { - 2 - } else { - 3 + 2 * g + table_shift - }; - STFS_BASE_OFFSET + (block_num + hash_before) * STFS_BLOCK_SIZE -} - -fn stfs_get_hash_entry(raw: &[u8], block_num: usize, table_shift: usize) -> Option { - let group = block_num / STFS_BLOCKS_PER_GRP; - let first_data = stfs_block_offset(group * STFS_BLOCKS_PER_GRP, table_shift); - let idx = (block_num % STFS_BLOCKS_PER_GRP) * 0x18; - for gap in &[2, 1] { - let hash_off = first_data - STFS_BLOCK_SIZE * gap; - let entry_off = hash_off + idx; - if entry_off + 0x18 > raw.len() { - continue; - } - let nxt = ((raw[entry_off + 0x15] as usize) << 16) - | ((raw[entry_off + 0x16] as usize) << 8) - | raw[entry_off + 0x17] as usize; - if nxt != 0xFFFFFF { - return Some(nxt); - } - } - None -} - -fn stfs_read_file(raw: &[u8], start: usize, size: usize, table_shift: usize) -> Vec { - let max_block = (raw.len().saturating_sub(STFS_BASE_OFFSET)) / STFS_BLOCK_SIZE; - let mut out = Vec::with_capacity(size); - let mut blk = start; - let mut rem = size; - while rem > 0 { - let off = stfs_block_offset(blk, table_shift); - let end = (off + STFS_BLOCK_SIZE).min(raw.len()); - if off >= raw.len() { - break; - } - let chunk = &raw[off..end]; - let take = rem.min(chunk.len()); - out.extend_from_slice(&chunk[..take]); - rem -= take; - match stfs_get_hash_entry(raw, blk, table_shift) { - Some(nxt) if nxt > 0 && nxt < max_block => blk = nxt, - _ => blk += 1, - } - } - out -} - -struct StfsPackage { - raw: Vec, - table_shift: usize, -} - -impl StfsPackage { - const DISP_OFF: usize = 0x0411; - const DISP_LEN: usize = 128; - const THUMB_OFF: usize = 0x171A; - fn new(raw: Vec) -> Result { - if raw.len() < 4 || raw[..4] != STFS_MAGIC { - return Err(format!( - "Not an STFS CON file (magic={:?})", - &raw[..4.min(raw.len())] - )); - } - Ok(Self { - raw, - table_shift: 1, - }) - } - - fn read_block(&self, b: usize) -> Vec { - let o = stfs_block_offset(b, self.table_shift); - let end = (o + STFS_BLOCK_SIZE).min(self.raw.len()); - self.raw[o..end].to_vec() - } - - fn display_name(&self) -> String { - let start = Self::DISP_OFF; - let end = (start + Self::DISP_LEN * 2).min(self.raw.len()); - let nb = &self.raw[start..end]; - let mut name = String::new(); - let mut i = 0; - while i + 1 < nb.len() { - let c = u16::from_be_bytes([nb[i], nb[i + 1]]); - if c == 0 { - break; - } - if let Some(ch) = char::from_u32(c as u32) { - name.push(ch); - } - i += 2; - } - if name.is_empty() { - "Unknown".to_string() - } else { - name - } - } - - fn thumbnail(&self) -> Option> { - let png_magic = b"\x89PNG\r\n\x1a\n"; - let search_start = Self::THUMB_OFF; - let idx = self.raw[search_start..] - .windows(png_magic.len()) - .position(|w| w == png_magic)?; - let abs_idx = search_start + idx; - let iend = self.raw[abs_idx..].windows(4).position(|w| w == b"IEND")?; - let abs_iend = abs_idx + iend; - Some(self.raw[abs_idx..(abs_iend + 12).min(self.raw.len())].to_vec()) - } - - fn file_table(&self) -> Vec { - let ft_block = (self.raw[0x37E] as usize) - | ((self.raw[0x37F] as usize) << 8) - | ((self.raw[0x380] as usize) << 16); - let blk_data = self.read_block(ft_block); - let mut entries = Vec::new(); - for i in 0..64 { - let base = i * 64; - if base + 64 > blk_data.len() { - break; - } - let e = &blk_data[base..base + 64]; - let name_len = (e[0x28] & 0x3F) as usize; - if name_len == 0 { - continue; - } - if (e[0x28] >> 6) & 0x02 != 0 { - continue; - } - let name: String = e[..name_len].iter().map(|&b| b as char).collect(); - let start_block = (e[0x2F] as usize) - | ((e[0x30] as usize) << 8) - | ((e[0x31] as usize) << 16); - let file_size = - u32::from_be_bytes([e[0x34], e[0x35], e[0x36], e[0x37]]) as usize; - if !name.is_empty() && file_size > 0 { - entries.push(StfsEntry { - name, - start_block, - size: file_size, - }); - } - } - entries - } - - fn extract_savegame_dat(&self) -> Option> { - for cand in &["savegame.dat", "SAVEGAME.DAT"] { - for entry in self.file_table() { - if entry.name.to_lowercase() == cand.to_lowercase() { - return Some(stfs_read_file( - &self.raw, - entry.start_block, - entry.size, - self.table_shift, - )); - } - } - } - None - } -} - -fn parse_region_filename(name: &str) -> Option<(&'static str, i32, i32)> { - let n = name.to_lowercase().replace('\\', "/"); - if let Some(rest) = n.strip_prefix("dim1/r.") { - if let Some(coords) = rest.strip_suffix(".mcr") { - let dot_pos = coords.find('.')?; - let x = coords[..dot_pos].parse().ok()?; - let z = coords[dot_pos + 1..].parse().ok()?; - return Some(("end", x, z)); - } - } - if let Some(rest) = n.strip_prefix("dim-1r.") { - if let Some(coords) = rest.strip_suffix(".mcr") { - let dot_pos = coords.find('.')?; - let x = coords[..dot_pos].parse().ok()?; - let z = coords[dot_pos + 1..].parse().ok()?; - return Some(("nether", x, z)); - } - } - if let Some(rest) = n.strip_prefix("r.") { - if let Some(coords) = rest.strip_suffix(".mcr") { - let dot_pos = coords.find('.')?; - let x = coords[..dot_pos].parse().ok()?; - let z = coords[dot_pos + 1..].parse().ok()?; - return Some(("overworld", x, z)); - } - } - None -} - -fn spawn_sig(axis: char) -> [u8; 9] { - let mut sig = [0u8; 9]; - sig[0] = 0x03; - sig[1] = 0x00; - sig[2] = 0x06; - sig[3..9].copy_from_slice(format!("Spawn{}", axis).as_bytes()); - sig -} - -fn read_spawn(level_dat: &[u8]) -> Option<(i32, i32, i32)> { - let mut coords = Vec::new(); - for axis in ['X', 'Y', 'Z'] { - let sig = spawn_sig(axis); - let idx = level_dat - .windows(sig.len()) - .position(|w| w == sig)?; - let val_off = idx + sig.len(); - if val_off + 4 > level_dat.len() { - return None; - } - coords.push(i32::from_be_bytes([ - level_dat[val_off], - level_dat[val_off + 1], - level_dat[val_off + 2], - level_dat[val_off + 3], - ])); - } - Some((coords[0], coords[1], coords[2])) -} - -fn patch_spawn(level_dat: &mut [u8], x: i32, y: i32, z: i32) { - for (axis, val) in [('X', x), ('Y', y), ('Z', z)] { - let sig = spawn_sig(axis); - if let Some(idx) = level_dat.windows(sig.len()).position(|w| w == sig) { - let val_off = idx + sig.len(); - if val_off + 4 <= level_dat.len() { - level_dat[val_off..val_off + 4].copy_from_slice(&val.to_be_bytes()); - } - } - } -} - -fn read_player_pos(player_dat: &[u8]) -> Option<(f64, f64, f64)> { - let idx = player_dat - .windows(PLAYER_POS_SIG.len()) - .position(|w| w == PLAYER_POS_SIG)?; - let p = idx + PLAYER_POS_SIG.len(); - if p + 24 > player_dat.len() { - return None; - } - let x = f64::from_be_bytes(player_dat[p..p + 8].try_into().ok()?); - let y = f64::from_be_bytes(player_dat[p + 8..p + 16].try_into().ok()?); - let z = f64::from_be_bytes(player_dat[p + 16..p + 24].try_into().ok()?); - Some((x, y, z)) -} - -fn patch_player_pos(player_dat: &mut [u8], x: f64, y: f64, z: f64) { - if let Some(idx) = player_dat - .windows(PLAYER_POS_SIG.len()) - .position(|w| w == PLAYER_POS_SIG) - { - let p = idx + PLAYER_POS_SIG.len(); - if p + 24 <= player_dat.len() { - player_dat[p..p + 8].copy_from_slice(&x.to_be_bytes()); - player_dat[p + 8..p + 16].copy_from_slice(&y.to_be_bytes()); - player_dat[p + 16..p + 24].copy_from_slice(&z.to_be_bytes()); - } - } -} - -fn compress_rle(data: &[u8]) -> Vec { - let mut out = Vec::new(); - let n = data.len(); - let mut i = 0; - while i < n { - let b = data[i]; - let mut run = 1usize; - while i + run < n && data[i + run] == b && run < 256 { - run += 1; - } - if b == 0xFF { - if run <= 3 { - out.push(0xFF); - out.push((run - 1) as u8); - } else { - out.push(0xFF); - out.push((run - 1) as u8); - out.push(0xFF); - } - } else if run < 4 { - out.extend(std::iter::repeat(b).take(run)); - } else { - out.push(0xFF); - out.push((run - 1) as u8); - out.push(b); - } - i += run; - } - out -} - -fn build_empty_chunk_nbt(chunk_x: i32, chunk_z: i32) -> Vec { - let mut out = Vec::new(); - out.extend_from_slice(b"\x0a\x00\x00"); - out.extend_from_slice(b"\x0a\x00\x05Level"); - out.extend_from_slice(b"\x07\x00\x06Blocks"); - out.extend_from_slice(&32768i32.to_be_bytes()); - out.extend(std::iter::repeat(0u8).take(32768)); - out.extend_from_slice(b"\x07\x00\x04Data"); - out.extend_from_slice(&16384i32.to_be_bytes()); - out.extend(std::iter::repeat(0u8).take(16384)); - out.extend_from_slice(b"\x07\x00\x08SkyLight"); - out.extend_from_slice(&16384i32.to_be_bytes()); - out.extend(std::iter::repeat(0xffu8).take(16384)); - out.extend_from_slice(b"\x07\x00\x0aBlockLight"); - out.extend_from_slice(&16384i32.to_be_bytes()); - out.extend(std::iter::repeat(0u8).take(16384)); - out.extend_from_slice(b"\x07\x00\x09HeightMap"); - out.extend_from_slice(&256i32.to_be_bytes()); - out.extend(std::iter::repeat(0u8).take(256)); - out.extend_from_slice(b"\x03\x00\x04xPos"); - out.extend_from_slice(&chunk_x.to_be_bytes()); - out.extend_from_slice(b"\x03\x00\x04zPos"); - out.extend_from_slice(&chunk_z.to_be_bytes()); - out.extend_from_slice(b"\x04\x00\x0aLastUpdate"); - out.extend_from_slice(&0i64.to_be_bytes()); - out.extend_from_slice(b"\x01\x00\x10TerrainPopulated\x01"); - out.extend_from_slice(b"\x09\x00\x08Entities\x0a\x00\x00\x00\x00"); - out.extend_from_slice(b"\x09\x00\x0cTileEntities\x0a\x00\x00\x00\x00"); //neo: someone send help - out.push(0x00); - out.push(0x00); - out -} - -fn find_safe_spawn( - dropped: &HashSet<(i32, i32)>, - orig: (i32, i32, i32), -) -> Option<(i32, i32, i32)> { - if dropped.is_empty() { - return None; - } - let (sx, sy, sz) = orig; - let sc_x = sx >> 4; - let sc_z = sz >> 4; - let too_close = |cx: i32, cz: i32| -> bool { - dropped - .iter() - .any(|&(dx, dz)| (cx - dx).abs().max((cz - dz).abs()) < 12) - }; - if !too_close(sc_x, sc_z) { - return None; - } - for radius in 1..200i32 { - for dz in -radius..=radius { - for dx in -radius..=radius { - if dx.abs().max(dz.abs()) != radius { - continue; - } - let cx = sc_x + dx; - let cz = sc_z + dz; - if !too_close(cx, cz) { - return Some((cx * 16 + 8, sy, cz * 16 + 8)); - } - } - } - } - None -} - -fn lzxd_window_from_bits(bits: usize) -> Option { - match bits { - 15 => Some(lzxd::WindowSize::KB32), - 16 => Some(lzxd::WindowSize::KB64), - 17 => Some(lzxd::WindowSize::KB128), - 18 => Some(lzxd::WindowSize::KB256), - 19 => Some(lzxd::WindowSize::KB512), - 20 => Some(lzxd::WindowSize::MB1), - 21 => Some(lzxd::WindowSize::MB2), - _ => None, - } -} - -fn try_lzxd(lzx_raw: &[u8], output_size: usize, window: lzxd::WindowSize) -> Option> { - let mut lzxd = lzxd::Lzxd::new(window); - lzxd.decompress_next(lzx_raw, output_size) - .ok() - .map(|slice| slice.to_vec()) -} - -fn decompress_region_chunk(xbox_data: &[u8]) -> Result, String> { - let hi = xbox_data[0]; - let (output_size, _src_sz, lzx_raw) = if hi == 0xFF { - let output_size = - ((xbox_data[1] as usize) << 8) | xbox_data[2] as usize; - let src_sz = - ((xbox_data[3] as usize) << 8) | xbox_data[4] as usize; - let lzx_raw = &xbox_data[5..(5 + src_sz).min(xbox_data.len())]; - (output_size, src_sz, lzx_raw) - } else { - let src_sz = - ((hi as usize) << 8) | xbox_data[1] as usize; - let lzx_raw = &xbox_data[2..(2 + src_sz).min(xbox_data.len())]; - (LZX_BLOCK_SIZE, src_sz, lzx_raw) - }; - - if let Some(out) = try_lzxd(lzx_raw, output_size, lzxd::WindowSize::KB128) { - return Ok(out); - } - for w in [16, 15, 18, 19, 20, 21] { - if let Some(ws) = lzxd_window_from_bits(w) { - if let Some(out) = try_lzxd(lzx_raw, output_size, ws) { - return Ok(out); - } - } - } - Err("LZX decode failed (all window sizes rejected the chunk)".to_string()) -} - -fn convert_region( - data: &[u8], - dropped_slots: &mut Vec, - region_coords: Option<(i32, i32)>, -) -> Result, String> { - let sect = 4096usize; - let mut buf = data.to_vec(); - for i in 0..REGION_SECT_COUNT * 2 { - if (i + 1) * 4 <= buf.len() { - s32(&mut buf, i * 4); - } - } - let mut chunk_positions: HashMap = HashMap::new(); - for slot in 0..REGION_SECT_COUNT { - if (slot + 1) * 4 > buf.len() { - break; - } - let off = u32::from_le_bytes([ - buf[slot * 4], - buf[slot * 4 + 1], - buf[slot * 4 + 2], - buf[slot * 4 + 3], - ]) as usize; - if off == 0 { - continue; - } - let sn = (off >> 8) & 0xFFFFFF; - let count = off & 0xFF; - if sn < 2 { - continue; - } - let fo = sn * sect; - if fo + 8 > data.len() { - continue; - } - chunk_positions.insert(fo, (slot, sn, count)); - } - if chunk_positions.is_empty() { - return Ok(buf); - } - let mut new_buf = vec![0u8; buf.len()]; - let copy_end = (sect * 2).min(buf.len()).min(new_buf.len()); - new_buf[..copy_end].copy_from_slice(&buf[..copy_end]); - let mut next_sector = 2usize; - let mut sorted_fos: Vec = chunk_positions.keys().copied().collect(); - sorted_fos.sort(); - for fo in sorted_fos { - let (slot, _sn, _count) = chunk_positions[&fo]; - let raw_comp_len = u32::from_be_bytes([ - data[fo], - data[fo + 1], - data[fo + 2], - data[fo + 3], - ]); - let raw_decomp_len = u32::from_be_bytes([ - data[fo + 4], - data[fo + 5], - data[fo + 6], - data[fo + 7], - ]); - let use_rle = (raw_comp_len & 0x80000000) != 0; - let comp_len = (raw_comp_len & 0x7FFFFFFF) as usize; - let decomp_len = raw_decomp_len as usize; - if comp_len == 0 || fo + 8 + comp_len > data.len() { - continue; - } - let xbox_data = &data[fo + 8..fo + 8 + comp_len]; - let rle_data = match decompress_region_chunk(xbox_data) { - Ok(d) => d, - Err(_) => { - dropped_slots.push(slot); - if let Some((rx, rz)) = region_coords { - let cx = rx * 32 + (slot % 32) as i32; - let cz = rz * 32 + (slot / 32) as i32; - let synth_nbt = build_empty_chunk_nbt(cx, cz); - let synth_rle = compress_rle(&synth_nbt); - let mut synth_encoder = - flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::new(6)); - let _ = synth_encoder.write_all(&synth_rle); - let synth_zlib = synth_encoder.finish().unwrap_or_default(); - let new_comp_len = synth_zlib.len(); - let needed = (8 + new_comp_len + sect - 1) / sect; - let dest_off = next_sector * sect; - while dest_off + 8 + new_comp_len > new_buf.len() { - new_buf.extend(std::iter::repeat(0u8).take(sect)); - } - new_buf[dest_off..dest_off + 4] - .copy_from_slice(&(new_comp_len as u32 | 0x80000000).to_le_bytes()); - new_buf[dest_off + 4..dest_off + 8] - .copy_from_slice(&(synth_nbt.len() as u32).to_le_bytes()); - new_buf[dest_off + 8..dest_off + 8 + new_comp_len] - .copy_from_slice(&synth_zlib); - new_buf[slot * 4..slot * 4 + 4] - .copy_from_slice(&((next_sector << 8) | needed).to_le_bytes()); - next_sector += needed; - } else { - new_buf[slot * 4..slot * 4 + 4].copy_from_slice(&0u32.to_le_bytes()); - } - continue; - } - }; - let zlib_data = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::new(6)); - let mut encoder = zlib_data; - encoder.write_all(&rle_data).map_err(|e| e.to_string())?; - let zlib_data = encoder.finish().map_err(|e| e.to_string())?; - let new_comp_len = zlib_data.len(); - let needed = (8 + new_comp_len + sect - 1) / sect; - let dest_off = next_sector * sect; - while dest_off + 8 + new_comp_len > new_buf.len() { - new_buf.extend(std::iter::repeat(0u8).take(sect)); - } - let comp_flag = if use_rle { - new_comp_len as u32 | 0x80000000 - } else { - new_comp_len as u32 - }; - new_buf[dest_off..dest_off + 4].copy_from_slice(&comp_flag.to_le_bytes()); - new_buf[dest_off + 4..dest_off + 8].copy_from_slice(&(decomp_len as u32).to_le_bytes()); - new_buf[dest_off + 8..dest_off + 8 + new_comp_len].copy_from_slice(&zlib_data); - let new_off = (next_sector << 8) | needed; - new_buf[slot * 4..slot * 4 + 4].copy_from_slice(&(new_off as u32).to_le_bytes()); - next_sector += needed; - } - let end = (next_sector * sect).min(new_buf.len()); - new_buf.truncate(end); - Ok(new_buf) -} - -fn convert_region_ps3(data: &[u8]) -> Result, String> { - let sect = 4096usize; - let mut buf = data.to_vec(); - for i in 0..REGION_SECT_COUNT * 2 { - if (i + 1) * 4 <= buf.len() { - s32(&mut buf, i * 4); - } - } - let mut chunk_positions: HashMap = HashMap::new(); - for slot in 0..REGION_SECT_COUNT { - if (slot + 1) * 4 > buf.len() { - break; - } - let off = u32::from_le_bytes([ - buf[slot * 4], - buf[slot * 4 + 1], - buf[slot * 4 + 2], - buf[slot * 4 + 3], - ]) as usize; - if off == 0 { - continue; - } - let sn = (off >> 8) & 0xFFFFFF; - let count = off & 0xFF; - if sn < 2 { - continue; - } - let fo = sn * sect; - if fo + 8 > data.len() { - continue; - } - chunk_positions.insert(fo, (slot, sn, count)); - } - if chunk_positions.is_empty() { - return Ok(buf); - } - let mut new_buf = vec![0u8; buf.len()]; - let copy_end = (sect * 2).min(buf.len()).min(new_buf.len()); - new_buf[..copy_end].copy_from_slice(&buf[..copy_end]); - let mut next_sector = 2usize; - let mut sorted_fos: Vec = chunk_positions.keys().copied().collect(); - sorted_fos.sort(); - for fo in sorted_fos { - let (slot, _sn, _count) = chunk_positions[&fo]; - let raw_comp_len = u32::from_be_bytes([ - data[fo], - data[fo + 1], - data[fo + 2], - data[fo + 3], - ]); - let raw_decomp_len = u32::from_be_bytes([ - data[fo + 4], - data[fo + 5], - data[fo + 6], - data[fo + 7], - ]); - let use_rle = (raw_comp_len & 0x80000000) != 0; - let comp_len = (raw_comp_len & 0x7FFFFFFF) as usize; - let decomp_len = raw_decomp_len as usize; - if comp_len == 0 || fo + 8 + comp_len > data.len() { - continue; - } - let chunk_body = &data[fo + 8..fo + 8 + comp_len]; - if chunk_body.len() < 5 { - new_buf[slot * 4..slot * 4 + 4].copy_from_slice(&0u32.to_le_bytes()); - continue; - } - let mut decoder = flate2::read::DeflateDecoder::new(&chunk_body[4..]); - let mut rle_data = Vec::new(); - if decoder.read_to_end(&mut rle_data).is_err() { - new_buf[slot * 4..slot * 4 + 4].copy_from_slice(&0u32.to_le_bytes()); - continue; - } - let mut encoder = - flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::new(6)); - encoder.write_all(&rle_data).map_err(|e| e.to_string())?; - let zlib_data = encoder.finish().map_err(|e| e.to_string())?; - let new_comp_len = zlib_data.len(); - let needed = (8 + new_comp_len + sect - 1) / sect; - let dest_off = next_sector * sect; - while dest_off + 8 + new_comp_len > new_buf.len() { - new_buf.extend(std::iter::repeat(0u8).take(sect)); - } - let comp_flag = if use_rle { - new_comp_len as u32 | 0x80000000 - } else { - new_comp_len as u32 - }; - new_buf[dest_off..dest_off + 4].copy_from_slice(&comp_flag.to_le_bytes()); - new_buf[dest_off + 4..dest_off + 8].copy_from_slice(&(decomp_len as u32).to_le_bytes()); - new_buf[dest_off + 8..dest_off + 8 + new_comp_len].copy_from_slice(&zlib_data); - let new_off = (next_sector << 8) | needed; - new_buf[slot * 4..slot * 4 + 4].copy_from_slice(&(new_off as u32).to_le_bytes()); - next_sector += needed; - } - let end = (next_sector * sect).min(new_buf.len()); - new_buf.truncate(end); - Ok(new_buf) -} - -fn decompress_xmemcompress(dat: &[u8]) -> Result, String> { - if dat.len() < 8 { - return Err("savegame.dat too small".to_string()); - } - let meta_off = u32::from_be_bytes([dat[0], dat[1], dat[2], dat[3]]) as usize; - if meta_off > dat.len() { - return Err("invalid metadata offset".to_string()); - } - let lzx_stream = &dat[8..meta_off]; - if lzx_stream.len() < 4 { - return Err("LZX stream too small".to_string()); - } - let uncomp_total = u32::from_be_bytes([ - lzx_stream[0], - lzx_stream[1], - lzx_stream[2], - lzx_stream[3], - ]) as usize; - let mut lzxd = lzxd::Lzxd::new(lzxd::WindowSize::KB128); - let mut output = Vec::with_capacity(uncomp_total); - let mut pos = 4; - while pos < lzx_stream.len() && output.len() < uncomp_total { - let hi = lzx_stream[pos]; - let (src_sz, dst_sz, header_len) = if hi == 0xFF { - if pos + 5 > lzx_stream.len() { - break; - } - let dst_sz = ((lzx_stream[pos + 1] as usize) << 8) | lzx_stream[pos + 2] as usize; - let src_sz = ((lzx_stream[pos + 3] as usize) << 8) | lzx_stream[pos + 4] as usize; - (src_sz, dst_sz, 5) - } else { - if pos + 2 > lzx_stream.len() { - break; - } - let src_sz = ((hi as usize) << 8) | lzx_stream[pos + 1] as usize; - (src_sz, LZX_BLOCK_SIZE, 2) - }; - pos += header_len; - if src_sz == 0 || dst_sz == 0 { - break; - } - if pos + src_sz > lzx_stream.len() { - break; - } - let lzx_raw = &lzx_stream[pos..pos + src_sz]; - let remaining = uncomp_total - output.len(); - let out_sz = dst_sz.min(remaining); - match lzxd.decompress_next(lzx_raw, out_sz) { - Ok(decompressed) => output.extend_from_slice(decompressed), - Err(e) => { - return Err(format!("LZX decompression failed at offset {}: {}", pos, e)) - } - } - pos += src_sz; - } - Ok(output) -} - -fn patch_level_name(nbt: &[u8], new_name: &str) -> Vec { - let idx = match nbt - .windows(LEVELNAME_SIG.len()) - .position(|w| w == LEVELNAME_SIG) - { - Some(i) => i, - None => return nbt.to_vec(), - }; - let str_off = idx + LEVELNAME_SIG.len(); - if str_off + 2 > nbt.len() { - return nbt.to_vec(); - } - let old_len = u16::from_be_bytes([nbt[str_off], nbt[str_off + 1]]) as usize; - let end = str_off + 2 + old_len; - let mut new_val = new_name.as_bytes().to_vec(); - if new_val.len() > 0xFFFF { - new_val.truncate(0xFFFF); - } - let mut payload = Vec::with_capacity(2 + new_val.len()); - payload.extend_from_slice(&(new_val.len() as u16).to_be_bytes()); - payload.extend_from_slice(&new_val); - let mut out = Vec::with_capacity(str_off + payload.len() + nbt.len().saturating_sub(end)); - out.extend_from_slice(&nbt[..str_off]); - out.extend_from_slice(&payload); - if end < nbt.len() { - out.extend_from_slice(&nbt[end..]); - } - out -} - -fn parse_param_sfo(path: &Path) -> HashMap { - let data = match fs::read(path) { - Ok(d) => d, - Err(_) => return HashMap::new(), - }; - if data.len() < 0x14 || &data[..4] != b"\x00PSF" { - return HashMap::new(); - } - let key_tbl = u32::from_le_bytes(data[8..12].try_into().unwrap()) as usize; - let data_tbl = u32::from_le_bytes(data[12..16].try_into().unwrap()) as usize; - let entries = u32::from_le_bytes(data[16..20].try_into().unwrap()) as usize; - let mut result = HashMap::new(); - for i in 0..entries { - let e = 0x14 + i * 16; - if e + 16 > data.len() { - break; - } - let key_off = u16::from_le_bytes([data[e], data[e + 1]]) as usize; - let fmt = u16::from_le_bytes([data[e + 2], data[e + 3]]); - let dlen = u16::from_le_bytes([data[e + 4], data[e + 5]]) as usize; - let doff = u32::from_le_bytes(data[e + 8..e + 12].try_into().unwrap()) as usize; - let ka = key_tbl + key_off; - let ke = data[ka..] - .iter() - .position(|&b| b == 0) - .map(|p| ka + p) - .unwrap_or(data.len()); - let key = String::from_utf8_lossy(&data[ka..ke]).to_string(); - let da = data_tbl + doff; - let val = if (fmt == SFO_FMT_UTF8_RAW || fmt == SFO_FMT_UTF8_STR) && da + dlen <= data.len() - { - let raw = &data[da..da + dlen]; - let null_pos = raw.iter().position(|&b| b == 0).unwrap_or(raw.len()); - String::from_utf8_lossy(&raw[..null_pos]).to_string() - } else if fmt == SFO_FMT_INT32 && da + 4 <= data.len() { - u32::from_le_bytes(data[da..da + 4].try_into().unwrap()).to_string() - } else { - continue; - }; - result.insert(key, val); - } - result -} - -fn looks_like_4j_header(data: &[u8]) -> bool { - if data.len() < 12 { - return false; - } - let (ho, ne, _ov, cv) = read_hdr_be(data); - if ho < 12 || ho as usize >= data.len() { - return false; - } - if data.len() - ho as usize != ne as usize * FILE_ENTRY_SIZE { - return false; - } - if ne == 0 || ne > 4096 { - return false; - } - if cv < 0 || cv > 20 { - return false; - } - true -} - -fn convert_bin_to_win64(bin_path: &str, game_dir: &str) -> Result { - let raw = fs::read(bin_path).map_err(|e| format!("Failed to read file: {}", e))?; - let pkg = StfsPackage::new(raw)?; - let name = pkg.display_name(); - let dat = pkg - .extract_savegame_dat() - .ok_or("savegame.dat not found in STFS package")?; - let decompressed = decompress_xmemcompress(&dat)?; - let (ho, ne, ov, cv) = read_hdr_be(&decompressed); - let entries = parse_ftable_be(&decompressed, ho, ne); - let mut file_blobs: Vec> = Vec::new(); - let mut dropped_overworld: HashSet<(i32, i32)> = HashSet::new(); - for e in &entries { - let fn_lower = e.filename.to_lowercase(); - let s = e.start_offset as usize; - let l = e.length as usize; - let raw_file = if s + l <= decompressed.len() { - decompressed[s..s + l].to_vec() - } else { - Vec::new() - }; - if fn_lower.ends_with(".mcr") && !raw_file.is_empty() { - let dim_info = parse_region_filename(&e.filename); - let region_xy = dim_info.map(|d| (d.1, d.2)); - let mut slots = Vec::new(); - let converted = - convert_region(&raw_file, &mut slots, region_xy)?; - if let Some(("overworld", rx, rz)) = dim_info { - for slot in slots { - let cx = rx * 32 + (slot % 32) as i32; - let cz = rz * 32 + (slot / 32) as i32; - dropped_overworld.insert((cx, cz)); - } - } - file_blobs.push(converted); - } else { - file_blobs.push(raw_file); - } - } - if !dropped_overworld.is_empty() { - let mut new_spawn: Option<(i32, i32, i32)> = None; - let mut spawn: Option<(i32, i32, i32)> = None; - for (i, e) in entries.iter().enumerate() { - if e.filename.to_lowercase() != "level.dat" { - continue; - } - spawn = read_spawn(&file_blobs[i]); - if let Some(s) = spawn { - if let Some(ns) = find_safe_spawn(&dropped_overworld, s) { - let blob = &mut file_blobs[i]; - patch_spawn(blob, ns.0, ns.1, ns.2); - new_spawn = Some(ns); - } - } - break; - } - let safe = new_spawn.or(spawn); - if let Some((sx, sy, sz)) = safe { - let _sx_chunk = sx >> 4; - let _sz_chunk = sz >> 4; - let too_close = |cx: i32, cz: i32| -> bool { - dropped_overworld - .iter() - .any(|&(dx, dz)| (cx - dx).abs().max((cz - dz).abs()) < 12) - }; - let mut moved_players = 0i32; - for (i, e) in entries.iter().enumerate() { - if !e.filename.starts_with("players/") || !e.filename.ends_with(".dat") { - continue; - } - if let Some((px, _py, pz)) = read_player_pos(&file_blobs[i]) { - let cx = px as i32 / 16; - let cz = pz as i32 / 16; - if too_close(cx, cz) { - let blob = &mut file_blobs[i]; - patch_player_pos(blob, sx as f64 + 0.5, sy as f64, sz as f64 + 0.5); - moved_players += 1; - } - } - } - if moved_players > 0 { - eprintln!("Relocated {} player(s) to safe spawn", moved_players); - } - } - } - let header_size = 12usize; - let mut body = Vec::new(); - let mut new_entries: Vec = Vec::new(); - let mut cursor = header_size; - for (i, e) in entries.iter().enumerate() { - let blob = &file_blobs[i]; - new_entries.push(FileEntry { - filename: e.filename.clone(), - length: blob.len() as u32, - start_offset: cursor as u32, - last_mod: e.last_mod, - }); - body.extend_from_slice(blob); - cursor += blob.len(); - } - let new_fto = cursor; - let out_cv = if cv <= 9 { cv } else { 9 }; - let mut header = Vec::with_capacity(header_size); - header.extend_from_slice(&(new_fto as u32).to_le_bytes()); - header.extend_from_slice(&(entries.len() as u32).to_le_bytes()); - header.extend_from_slice(&ov.to_le_bytes()); - header.extend_from_slice(&out_cv.to_le_bytes()); - let mut raw_le = Vec::with_capacity(header.len() + body.len() + ne as usize * FILE_ENTRY_SIZE); - raw_le.extend_from_slice(&header); - raw_le.extend_from_slice(&body); - for ne_entry in &new_entries { - let fn_bytes: Vec = ne_entry.filename.encode_utf16().map(|c| c.to_le()).collect(); - let mut fn_padded = vec![0u16; 64]; - for (j, &c) in fn_bytes.iter().take(64).enumerate() { - fn_padded[j] = c; - } - for &c in &fn_padded { - raw_le.extend_from_slice(&c.to_le_bytes()); - } - raw_le.extend_from_slice(&ne_entry.length.to_le_bytes()); - raw_le.extend_from_slice(&ne_entry.start_offset.to_le_bytes()); - raw_le.extend_from_slice(&ne_entry.last_mod.to_le_bytes()); - } - let mut encoder = - flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::new(6)); - encoder.write_all(&raw_le).map_err(|e| e.to_string())?; - let compressed = encoder.finish().map_err(|e| e.to_string())?; - let mut win64 = Vec::with_capacity(8 + compressed.len()); - win64.extend_from_slice(&0u32.to_le_bytes()); - win64.extend_from_slice(&(raw_le.len() as u32).to_le_bytes()); - win64.extend_from_slice(&compressed); - let folder = sanitise(&name); - let dst = Path::new(game_dir).join(&folder); - fs::create_dir_all(&dst).map_err(|e| format!("Failed to create output directory: {}", e))?; - fs::write(dst.join("saveData.ms"), &win64) - .map_err(|e| format!("Failed to write saveData.ms: {}", e))?; - if let Some(thumb) = pkg.thumbnail() { - let thumb_dir = dst.join("thumbnails"); - let _ = fs::create_dir_all(&thumb_dir); - let _ = fs::write(thumb_dir.join("thumbData.png"), &thumb); - } - Ok(dst.to_string_lossy().to_string()) -} - -fn convert_ps3_to_win64(ps3_save_dir: &str, game_dir: &str) -> Result { - let src = Path::new(ps3_save_dir); - if !src.is_dir() { - return Err(format!( - "'{}' is not a folder", - src.display() - )); - } - let gamedata_path = src.join("GAMEDATA"); - if !gamedata_path.exists() { - return Err(format!( - "GAMEDATA not found in {}", - src.file_name().unwrap_or_default().to_string_lossy() - )); - } - let sfo = parse_param_sfo(&src.join("PARAM.SFO")); - let save_title = sfo - .get("SUB_TITLE") - .cloned() - .unwrap_or_else(|| { - src.file_name() - .unwrap_or_default() - .to_string_lossy() - .to_string() - }); - let decompressed = - fs::read(&gamedata_path).map_err(|e| format!("Failed to read GAMEDATA: {}", e))?; - if !looks_like_4j_header(&decompressed) { - return Err("GAMEDATA does not look like a valid Minecraft PS3 save".to_string()); - } - let (ho, ne, ov, _cv) = read_hdr_be(&decompressed); - let entries = parse_ftable_be(&decompressed, ho, ne); - let mut file_blobs: Vec> = Vec::new(); - for e in &entries { - let fn_lower = e.filename.to_lowercase(); - let s = e.start_offset as usize; - let l = e.length as usize; - let mut raw_file = if s + l <= decompressed.len() { - decompressed[s..s + l].to_vec() - } else { - Vec::new() - }; - if fn_lower.ends_with(".mcr") && !raw_file.is_empty() { - raw_file = convert_region_ps3(&raw_file)?; - } else if fn_lower == "level.dat" && !save_title.is_empty() && !raw_file.is_empty() { - raw_file = patch_level_name(&raw_file, &save_title); - } - file_blobs.push(raw_file); - } - let header_size = 12usize; - let mut body = Vec::new(); - let mut new_entries: Vec = Vec::new(); - let mut cursor = header_size; - for (i, e) in entries.iter().enumerate() { - let blob = &file_blobs[i]; - new_entries.push(FileEntry { - filename: e.filename.clone(), - length: blob.len() as u32, - start_offset: cursor as u32, - last_mod: e.last_mod, - }); - body.extend_from_slice(blob); - cursor += blob.len(); - } - let new_fto = cursor; - let mut raw_le = Vec::with_capacity(header_size + body.len() + ne as usize * FILE_ENTRY_SIZE); - raw_le.extend_from_slice(&(new_fto as u32).to_le_bytes()); - raw_le.extend_from_slice(&ne.to_le_bytes()); - raw_le.extend_from_slice(&ov.to_le_bytes()); - raw_le.extend_from_slice(&9i16.to_le_bytes()); - raw_le.extend_from_slice(&body); - for ne_entry in &new_entries { - let fn_bytes: Vec = ne_entry.filename.encode_utf16().map(|c| c.to_le()).collect(); - let mut fn_padded = vec![0u16; 64]; - for (j, &c) in fn_bytes.iter().take(64).enumerate() { - fn_padded[j] = c; - } - for &c in &fn_padded { - raw_le.extend_from_slice(&c.to_le_bytes()); - } - raw_le.extend_from_slice(&ne_entry.length.to_le_bytes()); - raw_le.extend_from_slice(&ne_entry.start_offset.to_le_bytes()); - raw_le.extend_from_slice(&ne_entry.last_mod.to_le_bytes()); - } - let mut encoder = - flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::new(6)); - encoder.write_all(&raw_le).map_err(|e| e.to_string())?; - let compressed = encoder.finish().map_err(|e| e.to_string())?; - let mut win64 = Vec::with_capacity(8 + compressed.len()); - win64.extend_from_slice(&0u32.to_le_bytes()); - win64.extend_from_slice(&(raw_le.len() as u32).to_le_bytes()); - win64.extend_from_slice(&compressed); - let folder = sanitise(&save_title); - let dst = Path::new(game_dir).join(&folder); - fs::create_dir_all(&dst).map_err(|e| format!("Failed to create output directory: {}", e))?; - fs::write(dst.join("saveData.ms"), &win64) - .map_err(|e| format!("Failed to write saveData.ms: {}", e))?; - let thumb_path = src.join("THUMB"); - if thumb_path.exists() { - if let Ok(thumb_bytes) = fs::read(&thumb_path) { - if thumb_bytes.len() >= 8 && thumb_bytes[..8] == *b"\x89PNG\r\n\x1a\n" { - let thumb_dir = dst.join("thumbnails"); - let _ = fs::create_dir_all(&thumb_dir); - let _ = fs::write(thumb_dir.join("thumbData.png"), &thumb_bytes); - } - } - } - Ok(dst.to_string_lossy().to_string()) -} - -#[tauri::command] -#[allow(non_snake_case)] -pub async fn import_world( - _app: AppHandle, - input_path: String, - output_path: String, -) -> Result { - let output_parent = Path::new(&output_path).parent(); - if let Some(parent) = output_parent { - if !parent.exists() { - fs::create_dir_all(parent) - .map_err(|e| format!("Failed to create output directory {:?}: {}", parent, e))?; - } - } - fs::copy(&input_path, &output_path) - .map_err(|e| format!("Failed to copy .ms file: {}", e))?; - Ok(format!( - "World imported successfully!\nOutput: {}", - output_path - )) -} - -#[tauri::command] -#[allow(non_snake_case)] -pub async fn import_lce_save( - _app: AppHandle, - input_path: String, - output_dir: String, -) -> Result { - let path = Path::new(&input_path); - if path.is_file() { - let ext = path - .extension() - .unwrap_or_default() - .to_string_lossy() - .to_lowercase(); - if ext == "ms" { - let dst = Path::new(&output_dir); - fs::create_dir_all(dst) - .map_err(|e| format!("Failed to create output directory: {}", e))?; - fs::copy(&input_path, dst.join("saveData.ms")) - .map_err(|e| format!("Failed to copy .ms file: {}", e))?; - return Ok(dst.to_string_lossy().to_string()); - } - if ext == "bin" || ext == "" { - return convert_bin_to_win64(&input_path, &output_dir); - } - return Err(format!("Unrecognised file extension: .{}", ext)); - } - if path.is_dir() && path.join("GAMEDATA").is_file() { - return convert_ps3_to_win64(&input_path, &output_dir); - } - Err("Input is not a valid LCE save (expected .bin file, .ms file, or PS3 folder with GAMEDATA)".to_string()) -} diff --git a/src-tauri/src/commands/dlc.rs b/src-tauri/src/commands/dlc.rs deleted file mode 100644 index a0f0782..0000000 --- a/src-tauri/src/commands/dlc.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::fs; -use serde::Serialize; -use tauri::{AppHandle, Emitter}; -use crate::util; -use super::download::DownloadProgress; -#[derive(Serialize)] -pub struct GitEntry { - pub name: String, - pub is_dir: bool, -} - -fn parse_git_url(url: &str) -> Result<(String, String, String, bool), String> { - let parsed = url::Url::parse(url).map_err(|e| format!("Invalid URL: {}", e))?; - let host = parsed.host_str().ok_or("No host in URL")?.to_string(); - let segments: Vec<&str> = parsed.path().split('/').filter(|s| !s.is_empty()).collect(); - if segments.len() < 2 { - return Err("Invalid repo URL: need owner and repo".into()); - } - let owner = segments[0].to_string(); - let repo = segments[1].trim_end_matches(".git").to_string(); - let is_github = host == "github.com" || host == "raw.githubusercontent.com"; - Ok((owner, repo, host, is_github)) -} - -fn get_api_url(host: &str, owner: &str, repo: &str, path: &str, branch: &str, is_github: bool) -> String { - let api_path = if path.is_empty() || path == "." || path == "/" { - String::new() - } else { - format!("/{}", path.trim_start_matches('/')) - }; - if is_github { - format!("https://api.github.com/repos/{}/{}/contents{}?ref={}", owner, repo, api_path, branch) - } else { - format!("https://{}/api/v1/repos/{}/{}/contents{}?ref={}", host, owner, repo, api_path, branch) - } -} - -fn get_raw_url(host: &str, owner: &str, repo: &str, branch: &str, path: &str, is_github: bool) -> String { - if is_github { - format!("https://raw.githubusercontent.com/{}/{}/{}/{}", owner, repo, branch, path) - } else { - format!("https://{}/{}/{}/raw/branch/{}/{}", host, owner, repo, branch, path) - } -} - -#[tauri::command] -pub async fn list_git_directory( - app: tauri::AppHandle, - repo_url: String, - branch: String, - path: String, -) -> Result, String> { - list_git_directory_inner(app, repo_url, branch, path).await -} - -fn list_git_directory_inner( - app: tauri::AppHandle, - repo_url: String, - branch: String, - path: String, -) -> std::pin::Pin, String>> + Send>> { - Box::pin(async move { - let (owner, repo, host, is_github) = parse_git_url(&repo_url)?; - let api_url = get_api_url(&host, &owner, &repo, &path, &branch, is_github); - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let response = client.get(&api_url) - .send() - .await - .map_err(|e| format!("Failed to fetch directory listing: {}", e))?; - - if !response.status().is_success() { - if response.status().as_u16() == 404 { - return Ok(Vec::new()); - } - return Err(format!("Git API returned {}", response.status())); - } - - let text = response.text().await.map_err(|e| e.to_string())?; - let json: serde_json::Value = serde_json::from_str(&text).map_err(|e| format!("Failed to parse response: {}", e))?; - let entries = match &json { - serde_json::Value::Array(arr) => arr.clone(), - serde_json::Value::Object(_) => { - let is_dir = json.get("type").and_then(|v| v.as_str()) == Some("dir"); - if is_dir { - let sub_path = json.get("path").and_then(|v| v.as_str()).unwrap_or("").to_string(); - return list_git_directory_inner(app, repo_url, branch, sub_path).await; - } - return Ok(Vec::new()); - } - _ => return Ok(Vec::new()), - }; - - let mut result = Vec::new(); - for entry in &entries { - if let (Some(name), Some(type_val)) = ( - entry.get("name").and_then(|v| v.as_str()), - entry.get("type").and_then(|v| v.as_str()), - ) { - result.push(GitEntry { - name: name.to_string(), - is_dir: type_val == "dir", - }); - } - } - - Ok(result) - }) -} - -async fn collect_files( - app: &tauri::AppHandle, - host: &str, - owner: &str, - repo: &str, - branch: &str, - root_path: &str, - is_github: bool, -) -> Result, String> { - let mut files = Vec::new(); - let mut dirs_to_list = vec![root_path.to_string()]; - let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?; - while let Some(dir) = dirs_to_list.pop() { - let api_url = get_api_url(host, owner, repo, &dir, branch, is_github); - let response = client.get(&api_url) - .send() - .await - .map_err(|e| format!("Failed to list {}: {}", dir, e))?; - - if !response.status().is_success() { - return Err(format!("Failed to list {}: HTTP {}", dir, response.status())); - } - - let text = response.text().await.map_err(|e| e.to_string())?; - let json: serde_json::Value = serde_json::from_str(&text).map_err(|e| format!("Failed to parse: {}", e))?; - let entries = match &json { - serde_json::Value::Array(arr) => arr.clone(), - serde_json::Value::Object(_) => { - let entry_type = json.get("type").and_then(|v| v.as_str()).unwrap_or(""); - if entry_type == "dir" { - dirs_to_list.push(dir.clone()); - continue; - } - files.push(dir.clone()); - continue; - } - _ => continue, - }; - - for entry in &entries { - if let (Some(name), Some(type_val)) = ( - entry.get("name").and_then(|v| v.as_str()), - entry.get("type").and_then(|v| v.as_str()), - ) { - let full_path = if dir.is_empty() { name.to_string() } else { format!("{}/{}", dir, name) }; - if type_val == "dir" { - dirs_to_list.push(full_path); - } else { - files.push(full_path); - } - } - } - } - - Ok(files) -} - -#[tauri::command] -pub async fn download_dlc_files( - app: AppHandle, - instance_id: String, - repo_url: String, - branch: String, - dlc_folder: String, -) -> Result<(), String> { - let instance_dir = util::get_instance_working_dir(&app, &instance_id); - let dlc_dest = instance_dir.join("Windows64Media").join("DLC").join(&dlc_folder); - let (owner, repo, host, is_github) = parse_git_url(&repo_url)?; - let files_to_download = collect_files(&app, &host, &owner, &repo, &branch, &dlc_folder, is_github).await?; - if files_to_download.is_empty() { - return Err(format!("No files found in '{}' folder", dlc_folder)); - } - - fs::create_dir_all(&dlc_dest).map_err(|e| e.to_string())?; - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let total = files_to_download.len(); - for (i, file_path) in files_to_download.iter().enumerate() { - let raw_url = get_raw_url(&host, &owner, &repo, &branch, file_path, is_github); - let response = client.get(&raw_url) - .send() - .await - .map_err(|e| format!("Failed to download {}: {}", file_path, e))?; - - if !response.status().is_success() { - return Err(format!("Failed to download {}: HTTP {}", file_path, response.status())); - } - - let bytes = response.bytes().await.map_err(|e| e.to_string())?; - let relative_path = file_path.strip_prefix(&format!("{}/", dlc_folder)).unwrap_or(file_path); - let dest_path = dlc_dest.join(relative_path); - if let Some(parent) = dest_path.parent() { - fs::create_dir_all(parent).map_err(|e| e.to_string())?; - } - fs::write(&dest_path, &bytes).map_err(|e| format!("Failed to write {}: {}", file_path, e))?; - let _ = app.emit("download-progress", DownloadProgress { - instance_id: format!("dlc:{}", dlc_folder), - percent: ((i + 1) as f64 / total as f64) * 100.0, - }); - } - - Ok(()) -} diff --git a/src-tauri/src/commands/download.rs b/src-tauri/src/commands/download.rs deleted file mode 100644 index d39a483..0000000 --- a/src-tauri/src/commands/download.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::fs; -use std::io::Write; -use std::time::Duration; -use futures_util::StreamExt; -use serde::Serialize; -use tauri::{AppHandle, Emitter, State}; -use tokio_util::sync::CancellationToken; -use crate::state::DownloadState; -use crate::util; -#[derive(Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DownloadProgress { - pub instance_id: String, - pub percent: f64, -} - -async fn stream_download( - app: &AppHandle, - state: &DownloadState, - url: &str, - dest: &std::path::PathBuf, - instance_id: &str, -) -> Result { - let token = CancellationToken::new(); - let child_token = token.clone(); - { - let mut lock = state.tokens.lock().await; - lock.insert(instance_id.to_string(), token); - } - - let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?; - let response = client.get(url).send().await.map_err(|e| e.to_string())?; - if !response.status().is_success() { - { state.tokens.lock().await.remove(instance_id); } - return Err(format!("Download failed: {}", response.status())); - } - - let total_size = response.content_length().unwrap_or(0) as f64; - let last_modified = response.headers().get(reqwest::header::LAST_MODIFIED) - .and_then(|h| h.to_str().ok()) - .unwrap_or("") - .to_string(); - let mut file = fs::File::create(dest).map_err(|e| e.to_string())?; - let mut downloaded = 0.0; - let mut stream = response.bytes_stream(); - while let Some(chunk) = stream.next().await { - if child_token.is_cancelled() { - drop(file); - let _ = fs::remove_file(dest); - { state.tokens.lock().await.remove(instance_id); } - return Err("CANCELLED".into()); - } - let chunk = chunk.map_err(|e| e.to_string())?; - file.write_all(&chunk).map_err(|e| e.to_string())?; - downloaded += chunk.len() as f64; - if total_size > 0.0 { - let _ = app.emit("download-progress", DownloadProgress { - instance_id: instance_id.to_string(), - percent: downloaded / total_size * 100.0, - }); - } - } - - drop(file); - { state.tokens.lock().await.remove(instance_id); } - Ok(last_modified) -} - -async fn download_with_retry( - app: &AppHandle, - state: &DownloadState, - url: &str, - dest: &std::path::PathBuf, - instance_id: &str, - max_retries: u32, -) -> Result { - let mut last_error = String::new(); - for attempt in 1..=max_retries { - if attempt > 1 { - let backoff = Duration::from_secs(2u64.pow(attempt - 2)); - let cancel = CancellationToken::new(); - { - let mut lock = state.tokens.lock().await; - lock.insert(instance_id.to_string(), cancel.clone()); - } - let _ = app.emit("download-retry", attempt); - tokio::select! { - _ = tokio::time::sleep(backoff) => {} - _ = cancel.cancelled() => { - let _ = fs::remove_file(dest); - return Err("CANCELLED".into()); - } - } - } - match stream_download(app, state, url, dest, instance_id).await { - Ok(result) => return Ok(result), - Err(e) if e == "CANCELLED" => return Err(e), - Err(e) => { - last_error = e; - let _ = fs::remove_file(dest); - } - } - } - let _ = app.emit("backend-error", format!("Download failed after {max_retries} attempts: {last_error}")); - Err(last_error) -} - -#[tauri::command] -#[allow(non_snake_case)] -pub async fn download_and_install( - app: AppHandle, - state: State<'_, DownloadState>, - url: String, - instance_id: String, -) -> Result { - let instance_dir = util::get_instance_working_dir(&app, &instance_id); - let root = util::get_app_dir(&app); - let zip_path = root.join(format!("temp_{}.zip", instance_id)); - let last_modified = download_with_retry(&app, &state, &url, &zip_path, &instance_id, 3).await?; - let keep_list: std::collections::HashSet<&str> = [ - "Windows64", "Windows64Media", "uid.dat", "username.txt", "settings.dat", - "servers.dat", "servers.txt", "server.properties", "options.txt", "servers.db", - "workshop_files.json", "screenshots", "update_timestamp.txt", - "profile0.dat", "profile1.dat", "profile2.dat", "profile3.dat", - "profile4.dat", "profile5.dat", "profile6.dat", "profile7.dat", - "profile8.dat", "profile9.dat", "profile10.dat", "proton_prefix" - ].iter().copied().collect(); - - if !instance_dir.exists() { - fs::create_dir_all(&instance_dir).map_err(|e| e.to_string())?; - } else { - let workshop_files: std::collections::HashSet = { - let wf_path = instance_dir.join("workshop_files.json"); - fs::read_to_string(&wf_path) - .ok() - .and_then(|s| serde_json::from_str::>(&s).ok()) - .unwrap_or_default() - .into_iter() - .collect() - }; - - if let Ok(entries) = fs::read_dir(&instance_dir) { - for entry in entries.flatten() { - let file_name = entry.file_name(); - let name_str = file_name.to_string_lossy(); - let entry_path_str = entry.path().to_string_lossy().to_string(); - let is_workshop_file = workshop_files.iter().any(|wf| entry_path_str.starts_with(wf) || wf.starts_with(&entry_path_str)); - if !keep_list.contains(name_str.as_ref()) && !is_workshop_file { - let path = entry.path(); - if path.is_dir() { - let _ = fs::remove_dir_all(path); - } else { - let _ = fs::remove_file(path); - } - } - } - } - } - - if !last_modified.is_empty() { - let _ = fs::write(instance_dir.join("update_timestamp.txt"), &last_modified); - } - - #[cfg(target_os = "linux")] - { - let bsdtar_ok = std::process::Command::new("bsdtar") - .args(["-xf", zip_path.to_str().unwrap(), "-C", instance_dir.to_str().unwrap()]) - .status() - .map(|s| s.success()) - .unwrap_or(false); - - if !bsdtar_ok { - let unzip_ok = std::process::Command::new("unzip") - .args(["-o", zip_path.to_str().unwrap(), "-d", instance_dir.to_str().unwrap()]) - .status() - .map(|s| s.success()) - .unwrap_or(false); - - if !unzip_ok { - return Err("Extraction failed".into()); - } - } - } - - #[cfg(target_os = "android")] - { - let status = std::process::Command::new("unzip") - .args(["-o", zip_path.to_str().unwrap(), "-d", instance_dir.to_str().unwrap()]) - .status() - .map_err(|e| e.to_string())?; - if !status.success() { - return Err("Extraction failed".into()); - } - } - - #[cfg(all(not(target_os = "linux"), not(target_os = "android")))] - { - let mut cmd = std::process::Command::new("tar"); - cmd.args(["-xf", zip_path.to_str().unwrap(), "-C", instance_dir.to_str().unwrap()]); - #[cfg(target_os = "windows")] - { - use std::os::windows::process::CommandExt; - cmd.creation_flags(0x08000000); - } - let status = cmd.status().map_err(|e| e.to_string())?; - if !status.success() { - return Err("Extraction failed".into()); - } - } - - let _ = fs::remove_file(&zip_path); - if let Ok(entries) = fs::read_dir(&instance_dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - let check_exe = path.join("Minecraft.Client.exe"); - if check_exe.exists() { - let inner_dir = path; - if let Ok(inner_entries) = fs::read_dir(&inner_dir) { - for inner_entry in inner_entries.flatten() { - let file_name = inner_entry.file_name(); - let name_str = file_name.to_string_lossy(); - let dest_path = instance_dir.join(&file_name); - if keep_list.contains(name_str.as_ref()) && dest_path.exists() { - continue; - } - if fs::rename(inner_entry.path(), &dest_path).is_err() { - if inner_entry.path().is_dir() { - let _ = util::copy_dir_all(inner_entry.path(), &dest_path); - let _ = fs::remove_dir_all(inner_entry.path()); - } else { - let _ = fs::copy(inner_entry.path(), &dest_path); - let _ = fs::remove_file(inner_entry.path()); - } - } - } - } - let _ = fs::remove_dir_all(&inner_dir); - break; - } - } - } - } - - Ok("Success".into()) -} - -#[tauri::command] -pub async fn cancel_download(state: State<'_, DownloadState>, instance_id: String) -> Result<(), String> { - let token = state.tokens.lock().await.remove(&instance_id); - if let Some(t) = token { - t.cancel(); - } - Ok(()) -} - -#[tauri::command] -pub async fn download_runner( - app: AppHandle, - state: State<'_, DownloadState>, - name: String, - url: String, -) -> Result { - let runners_dir = util::get_app_dir(&app).join("runners"); - fs::create_dir_all(&runners_dir).map_err(|e| e.to_string())?; - let runner_dir = runners_dir.join(&name); - if runner_dir.exists() { - let _ = fs::remove_dir_all(&runner_dir); - } - fs::create_dir_all(&runner_dir).map_err(|e| e.to_string())?; - let tarball_path = runners_dir.join(format!("{}.tar.gz", name)); - let runner_id = format!("runner_{}", name); - download_with_retry(&app, &state, &url, &tarball_path, &runner_id, 3).await?; - let status = std::process::Command::new("tar") - .args(["-zxf", tarball_path.to_str().unwrap(), "-C", runner_dir.to_str().unwrap(), "--strip-components=1"]) - .status() - .map_err(|e| e.to_string())?; - - let _ = fs::remove_file(&tarball_path); - if !status.success() { - let _ = fs::remove_dir_all(&runner_dir); - return Err("Extraction failed".into()); - } - - Ok(name) -} - -#[tauri::command] -pub async fn check_game_update( - app: AppHandle, - instance_id: String, - url: String, -) -> Result { - let instance_dir = util::get_instance_working_dir(&app, &instance_id); - let timestamp_file = instance_dir.join("update_timestamp.txt"); - let local_timestamp = fs::read_to_string(×tamp_file).unwrap_or_default(); - if url.is_empty() { - return Ok(false); - } - if local_timestamp.is_empty() { - return Ok(true); - } - - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let response = client - .head(&url) - .send() - .await - .map_err(|e| e.to_string())?; - if let Some(remote_header) = response.headers().get(reqwest::header::LAST_MODIFIED) { - if let Ok(remote_timestamp) = remote_header.to_str() { - if remote_timestamp != local_timestamp { - return Ok(true); - } - } - } - - Ok(false) -} diff --git a/src-tauri/src/commands/file_dialogs.rs b/src-tauri/src/commands/file_dialogs.rs deleted file mode 100644 index 80c5ece..0000000 --- a/src-tauri/src/commands/file_dialogs.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::fs; -#[cfg(desktop)] -#[tauri::command] -pub fn pick_folder() -> Result { - let folder = rfd::FileDialog::new() - .set_title("Select Export Folder") - .pick_folder(); - - if let Some(path) = folder { - Ok(path.to_string_lossy().to_string()) - } else { - Err("CANCELED".into()) - } -} - -#[cfg(desktop)] -#[tauri::command] -pub fn pick_file(title: String, filters: Vec) -> Result { - let mut dialog = rfd::FileDialog::new().set_title(&title); - if !filters.is_empty() { - let filters_ref: Vec<&str> = filters.iter().map(|s| s.as_str()).collect(); - dialog = dialog.add_filter("Files", &filters_ref); - } - if let Some(path) = dialog.pick_file() { - Ok(path.to_string_lossy().to_string()) - } else { - Err("CANCELED".into()) - } -} - -#[cfg(desktop)] -#[tauri::command] -pub fn save_file_dialog(title: String, filename: String, filters: Vec) -> Result { - let mut dialog = rfd::FileDialog::new().set_title(&title).set_file_name(&filename); - if !filters.is_empty() { - let filters_ref: Vec<&str> = filters.iter().map(|s| s.as_str()).collect(); - dialog = dialog.add_filter("Files", &filters_ref); - } - if let Some(path) = dialog.save_file() { - Ok(path.to_string_lossy().to_string()) - } else { - Err("CANCELED".into()) - } -} - -#[tauri::command] -pub fn write_binary_file(path: String, data: Vec) -> Result<(), String> { - fs::write(path, data).map_err(|e| e.to_string()) -} - -#[tauri::command] -pub fn read_binary_file(path: String) -> Result, String> { - fs::read(path).map_err(|e| e.to_string()) -} diff --git a/src-tauri/src/commands/game.rs b/src-tauri/src/commands/game.rs deleted file mode 100644 index 822131d..0000000 --- a/src-tauri/src/commands/game.rs +++ /dev/null @@ -1,867 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use std::process::Stdio; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; -use tauri::{AppHandle, Emitter, Manager, State}; -use tauri_plugin_opener::OpenerExt; -use tokio::io::AsyncRead; -use tokio::io::AsyncReadExt; -use tokio::sync::Mutex; -use crate::commands::goldmapper; -use crate::commands::runners; -use crate::config; -use crate::types::AppConfig; -#[cfg(target_os = "macos")] -use crate::platform::macos; -#[cfg(unix)] -use crate::platform::linux; -use crate::playtime::{self, PlaytimeResponse, PlaytimeDayEntry}; -use crate::state::GameState; -use crate::types::McServer; -use crate::util; -use crate::workshop_server; -#[tauri::command] -#[allow(non_snake_case)] -pub async fn launch_game( - app: AppHandle, - state: State<'_, GameState>, - instance_id: String, - servers: Vec, - mut extra_args: Vec, -) -> Result<(), String> { - extra_args.extend(load_instance_args(&app, &instance_id)); - #[cfg(target_os = "android")] - { - let _ = state; - let mut servers = servers; - let working_dir = util::get_instance_working_dir(&app, &instance_id); - if !working_dir.join("Minecraft.Client.exe").exists() { - return Err("Game executable not found in instance folder.".into()); - } - - let config_val = config::load_config_raw(app.clone()); - let lce_online = McServer { name: "LCEOnline Game".into(), ip: "127.0.0.1".into(), port: 61000 }; - if !servers.iter().any(|s| s.ip == lce_online.ip && s.port == lce_online.port) { - servers.push(lce_online); - } - if let Some(ref saved) = config_val.saved_servers { - for s in saved { - if !servers.iter().any(|existing| existing.ip == s.ip && existing.port == s.port) { - servers.push(s.clone()); - } - } - } - ensure_server_list(&working_dir, servers); - - let result = crate::android_runtime::launch_bridge( - working_dir.to_string_lossy().to_string(), - crate::android_runtime::BridgeAction::Play, - extra_args, - ); - if result.is_ok() { - playtime::start_session(&app, &instance_id); - } - result - } - #[cfg(not(target_os = "android"))] - launch_game_desktop(app, state, instance_id, servers, extra_args).await -} - -#[cfg(not(target_os = "android"))] -async fn launch_game_desktop( - app: AppHandle, - state: State<'_, GameState>, - instance_id: String, - mut servers: Vec, - extra_args: Vec, -) -> Result<(), String> { - state.manual_stop.store(false, Ordering::SeqCst); - perform_instance_sync(&app, &instance_id).await?; - let working_dir = util::get_instance_working_dir(&app, &instance_id); - let config_val = config::load_config_raw(app.clone()); - let lce_online = McServer { name: "LCEOnline Game".into(), ip: "127.0.0.1".into(), port: 61000 }; - if !servers.iter().any(|s| s.ip == lce_online.ip && s.port == lce_online.port) { - servers.push(lce_online); - } - if let Some(ref saved) = config_val.saved_servers { - for s in saved { - if !servers.iter().any(|existing| existing.ip == s.ip && existing.port == s.port) { - servers.push(s.clone()); - } - } - } - ensure_server_list(&working_dir, servers); - let ws_cancel = workshop_server::start(app.clone()).await; - let _ws_guard = workshop_server::Guard::new(ws_cancel.clone()); - { - let mut lock = state.workshop_cancel.lock().await; - *lock = Some(ws_cancel); - } - - let game_exe = working_dir.join("Minecraft.Client.exe"); - if !game_exe.exists() { - return Err("Game executable not found in instance folder.".into()); - } - - #[cfg(target_os = "linux")] - { - if let Some(ref runner_id) = config_val.linux_runner { - let runners_list = runners::get_available_runners(app.clone()); - if let Some(runner) = runners_list.into_iter().find(|r| r.id == *runner_id) { - let is_proton = runner.r#type == "proton"; - let program = if is_proton { - PathBuf::from(&runner.path).join("proton").to_string_lossy().to_string() - } else { - runner.path.clone() - }; - let mut args: Vec = Vec::new(); - if is_proton { - args.push("run".to_string()); - } - let compat_data = if is_proton { - let cd = working_dir.join("proton_prefix"); - fs::create_dir_all(&cd).map_err(|e| e.to_string())?; - Some(cd) - } else { - None - }; - - let mangohud = config_val.mangohud_enabled.unwrap_or(false); - let (prog, runner_args): (&str, &[&str]) = if mangohud { - ("mangohud", &[&program]) - } else { - (&program, &[]) - }; - - let mut all_args: Vec = Vec::new(); - for a in runner_args { - all_args.push(a.to_string()); - } - all_args.extend(args.clone()); - let goldmapper_args = - goldmapper::build_launch_args(&app, &config_val, &game_exe, &extra_args)?; - if let Some(gm_args) = goldmapper_args { - all_args.extend(gm_args); - } else { - all_args.push(game_exe.to_string_lossy().to_string()); - all_args.extend(extra_args.clone()); - } - let (final_prog, final_args) = apply_launch_prefix(prog, all_args, &config_val); - let mut cmd = tokio::process::Command::new(&final_prog); - for a in &final_args { - cmd.arg(a); - } - - if is_proton { - let cd = compat_data.as_ref().unwrap(); - if std::env::var("STEAM_COMPAT_CLIENT_INSTALL_PATH").is_err() { - cmd.env("STEAM_COMPAT_CLIENT_INSTALL_PATH", ""); - } - cmd.env("STEAM_COMPAT_DATA_PATH", cd.to_str().unwrap()); - if std::env::var("SteamAppId").is_err() { - cmd.env("SteamAppId", "480"); - } - } - - #[cfg(unix)] - { - cmd.process_group(0); - cmd.env_remove("LD_PRELOAD"); - cmd.env_remove("PYTHONPATH"); - cmd.env_remove("PYTHONHOME"); - cmd.env_remove("LD_LIBRARY_PATH"); - cmd.env_remove("QT_PLUGIN_PATH"); - } - - apply_launch_env_vars(&mut cmd, &config_val); - cmd.current_dir(&working_dir); - cmd.env("WINEDEBUG", "+debugstr"); - let playtime_start = std::time::Instant::now(); - let Some(result) = run_game_and_capture(&state, cmd).await? else { - return Ok(()); - }; - - let duration = playtime_start.elapsed(); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let start = now - duration.as_secs(); - playtime::record_session(&app, &instance_id, start, now); - - return handle_game_exit(&app, &state, result); - } - } - Err("No Linux runner selected in settings.".into()) - } - - #[cfg(not(target_os = "linux"))] - { - #[cfg(target_os = "macos")] - { - let runtime_dir = macos::get_macos_runtime_dir(&app); - let toolkit_dir = runtime_dir.join("toolkit"); - let prefix_dir = runtime_dir.join("prefix"); - if !toolkit_dir.exists() || !prefix_dir.exists() { - return Err("macOS Compatibility is not set up. Open Settings and run Setup macOS Compatibility.".into()); - } - - let gptk_no_hud = macos::find_executable_recursive(&toolkit_dir, "gameportingtoolkit-no-hud") - .or_else(|| macos::find_executable_recursive(&toolkit_dir, "gameportingtoolkit")); - - let is_intel = std::env::consts::ARCH == "x86_64"; - let wine_binary = if is_intel { - macos::find_executable_recursive(&toolkit_dir, "wine") - .or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine64")) - } else { - macos::find_executable_recursive(&toolkit_dir, "wine64") - .or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine")) - } - .ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?; - - let wine_bin_dir = wine_binary - .parent() - .map(|pp| pp.to_path_buf()) - .ok_or_else(|| "Unable to locate wine bin directory inside runtime.".to_string())?; - - let (mac_prog, mut mac_args): (String, Vec) = if let Some(ref wrapper) = gptk_no_hud { - let win_path = util::unix_path_to_wine_z_path(&game_exe); - (wrapper.to_string_lossy().to_string(), vec![ - prefix_dir.to_string_lossy().to_string(), - win_path, - ]) - } else { - (wine_binary.to_string_lossy().to_string(), vec![ - game_exe.to_string_lossy().to_string(), - ]) - }; - - let goldmapper_args = - goldmapper::build_launch_args(&app, &config_val, &game_exe, &extra_args)?; - if let Some(gm_args) = goldmapper_args { - mac_args.extend(gm_args); - } else { - mac_args.extend(extra_args.clone()); - } - - let (final_prog, final_args) = apply_launch_prefix(&mac_prog, mac_args, &config_val); - let mut cmd = tokio::process::Command::new(&final_prog); - for a in &final_args { - cmd.arg(a); - } - - #[cfg(unix)] - cmd.process_group(0); - - apply_launch_env_vars(&mut cmd, &config_val); - cmd.current_dir(&working_dir); - cmd.env("WINEPREFIX", &prefix_dir); - cmd.env("WINEDEBUG", "+debugstr"); - let perf_boost = config_val.apple_silicon_performance_boost.unwrap_or(false); - if perf_boost { - #[cfg(target_arch = "aarch64")] - { - cmd.env("WINE_MSYNC", "1"); - cmd.env("MVK_ALLOW_METAL_FENCES", "1"); - } - #[cfg(not(target_arch = "aarch64"))] - { - cmd.env("WINEESYNC", "1"); - } - } else { - cmd.env("WINEESYNC", "1"); - } - cmd.env("WINEDLLOVERRIDES", "winemenubuilder.exe=d;mscoree,mshtml="); - cmd.env("MTL_HUD_ENABLED", "0"); - cmd.env("MVK_CONFIG_RESUME_LOST_DEVICE", "1"); - cmd.env( - "PATH", - format!( - "{}:{}", - wine_bin_dir.to_string_lossy(), - std::env::var("PATH").unwrap_or_default() - ), - ); - cmd.stdin(std::process::Stdio::null()); - - let playtime_start = std::time::Instant::now(); - let Some(result) = run_game_and_capture(&state, cmd).await? else { - return Ok(()); - }; - - let duration = playtime_start.elapsed(); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let start = now - duration.as_secs(); - playtime::record_session(&app, &instance_id, start, now); - - return handle_game_exit(&app, &state, result); - } - - #[cfg(all( - not(target_os = "macos"), - not(target_os = "linux"), - not(target_os = "android") - ))] - { - let goldmapper_args = - goldmapper::build_launch_args(&app, &config_val, &game_exe, &extra_args)?; - let (prog_str, all_args): (String, Vec) = match goldmapper_args { - Some(gm_args) => ( - gm_args[0].clone(), - gm_args[1..].to_vec(), - ), - None => (game_exe.to_string_lossy().to_string(), extra_args.clone()), - }; - let (final_prog, final_args) = apply_launch_prefix(&prog_str, all_args, &config_val); - let mut cmd = tokio::process::Command::new(&final_prog); - for a in &final_args { - cmd.arg(a); - } - #[cfg(target_os = "windows")] - cmd.creation_flags(0x08000000); - #[cfg(unix)] - cmd.process_group(0); - apply_launch_env_vars(&mut cmd, &config_val); - cmd.current_dir(&working_dir); - let playtime_start = std::time::Instant::now(); - let Some(result) = run_game_and_capture(&state, cmd).await? else { - return Ok(()); - }; - let duration = playtime_start.elapsed(); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let start = now - duration.as_secs(); - playtime::record_session(&app, &instance_id, start, now); - return handle_game_exit(&app, &state, result); - } - } -} - -#[tauri::command] -pub async fn stop_game( - app: AppHandle, - instance_id: String, - state: State<'_, GameState>, -) -> Result<(), String> { - state.manual_stop.store(true, Ordering::SeqCst); - let mut lock = state.child.lock().await; - if let Some(mut child) = lock.take() { - #[cfg(unix)] - linux::kill_process_tree(&app, &instance_id); - let _ = child.kill().await; - } - drop(lock); - - let mut lock = state.workshop_cancel.lock().await; - if let Some(cancel) = lock.take() { - cancel.cancel(); - } - Ok(()) -} - -#[tauri::command] -#[allow(non_snake_case)] -pub fn check_game_installed(app: AppHandle, instance_id: String) -> bool { - util::get_instance_working_dir(&app, &instance_id) - .join("Minecraft.Client.exe") - .exists() -} - -#[tauri::command] -#[allow(non_snake_case)] -pub fn open_instance_folder(app: AppHandle, instance_id: String) { - let folder = util::get_instance_working_dir(&app, &instance_id); - #[cfg(target_os = "android")] - { - let _ = std::fs::create_dir_all(&folder); - let _ = crate::android_runtime::launch_bridge( - folder.to_string_lossy().to_string(), - crate::android_runtime::BridgeAction::OpenContainer, - Vec::new(), - ); - } - #[cfg(not(target_os = "android"))] - { - if folder.exists() { - let _ = app.opener().open_path(folder.to_str().unwrap(), None::<&str>); - } - } -} - -#[tauri::command] -#[allow(non_snake_case)] -pub fn open_container_settings(app: AppHandle, instance_id: String) -> Result<(), String> { - #[cfg(target_os = "android")] - { - let folder = util::get_instance_working_dir(&app, &instance_id); - crate::android_runtime::launch_bridge( - folder.to_string_lossy().to_string(), - crate::android_runtime::BridgeAction::OpenSettings, - Vec::new(), - ) - } - #[cfg(not(target_os = "android"))] - { - let _ = (app, instance_id); - Err("Only supported on Android".into()) - } -} - -#[tauri::command] -#[allow(non_snake_case)] -pub fn delete_instance(app: AppHandle, instance_id: String) -> Result<(), String> { - let config_val = config::load_config_raw(app.clone()); - if let Some(ref editions) = config_val.custom_editions { - if let Some(edition) = editions.iter().find(|e| e.id == instance_id) { - if edition.path.is_some() { - return Ok(()); - } - } - } - if let Some(ref custom_paths) = config_val.custom_paths { - if custom_paths.contains_key(&instance_id) { - return Ok(()); - } - } - let dir = util::get_app_dir(&app).join("instances").join(&instance_id); - if dir.exists() { - let _ = fs::remove_dir_all(dir); - } - Ok(()) -} - -#[tauri::command] -pub async fn sync_dlc(app: AppHandle, instance_id: String) -> Result<(), String> { - perform_instance_sync(&app, &instance_id).await -} - -#[tauri::command] -pub fn get_instance_path(app: AppHandle, instance_id: String) -> String { - util::get_instance_working_dir(&app, &instance_id) - .to_string_lossy() - .to_string() -} - -fn load_instance_args(app: &AppHandle, instance_id: &str) -> Vec { - let config_val = config::load_config_raw(app.clone()); - config_val - .instance_launch_args - .and_then(|m| m.get(instance_id).cloned()) - .map(|entry| entry.args) - .unwrap_or_default() -} - -#[tauri::command] -pub fn get_instance_args_schema(app: AppHandle, instance_id: String) -> Option { - let dir = util::get_instance_working_dir(&app, &instance_id); - fs::read_to_string(dir.join("Arguments.Schema.json")).ok() -} - -#[tauri::command] -pub fn get_playtime(app: AppHandle, instance_id: String) -> PlaytimeResponse { - playtime::get_playtime(&app, &instance_id) -} - -#[tauri::command] -pub fn get_playtime_daily(app: AppHandle, instance_id: String, days: u64) -> Vec { - playtime::get_playtime_daily(&app, &instance_id, days) -} - -#[cfg(desktop)] -#[tauri::command] -pub fn backup_instance(app: AppHandle, instance_id: String) -> Result<(), String> { - let instance_dir = util::get_instance_working_dir(&app, &instance_id); - if !instance_dir.exists() { - return Err("Instance not found".into()); - } - - let backup_name = format!("{}_backup.tar.gz", instance_id); - let file = rfd::FileDialog::new() - .set_title("Save Instance Backup") - .set_file_name(&backup_name) - .add_filter("Tar Gzip Archive", &["tar.gz"]) - .save_file(); - - if let Some(path) = file { - let parent = instance_dir.parent().ok_or("Invalid instance path")?; - let dir_name = instance_dir.file_name().ok_or("Invalid dir name")?; - - let status = std::process::Command::new("tar") - .args(["-czf", path.to_str().unwrap(), "-C", parent.to_str().unwrap(), dir_name.to_str().unwrap()]) - .status() - .map_err(|e| format!("Failed to create backup: {}", e))?; - - if status.success() { - Ok(()) - } else { - Err("Backup command failed".into()) - } - } else { - Err("CANCELED".into()) - } -} - -#[cfg(desktop)] -#[tauri::command] -pub fn restore_instance(app: AppHandle) -> Result { - let file = rfd::FileDialog::new() - .set_title("Restore Instance Backup") - .add_filter("Tar Gzip Archive", &["tar.gz"]) - .add_filter("Zip Archive", &["zip"]) - .pick_file(); - - if let Some(path) = file { - let instances_dir = util::get_app_dir(&app).join("instances"); - std::fs::create_dir_all(&instances_dir).map_err(|e| e.to_string())?; - - let ext = path.extension().and_then(|s| s.to_str()).unwrap_or(""); - let status = if ext == "zip" { - std::process::Command::new("unzip") - .arg("-o") - .arg(path.to_str().unwrap()) - .arg("-d") - .arg(instances_dir.to_str().unwrap()) - .status() - .map_err(|e| format!("Failed to extract backup: {}", e))? - } else { - std::process::Command::new("tar") - .args(["-xzf", path.to_str().unwrap(), "-C", instances_dir.to_str().unwrap()]) - .status() - .map_err(|e| format!("Failed to extract backup: {}", e))? - }; - - if status.success() { - let extracted: Vec<_> = std::fs::read_dir(&instances_dir) - .map_err(|e| e.to_string())? - .filter_map(|e| e.ok()) - .filter(|e| e.path().is_dir() && e.path().join("Minecraft.Client.exe").exists()) - .collect(); - - if let Some(new_instance) = extracted.into_iter().next() { - let id = new_instance.file_name().to_string_lossy().to_string(); - Ok(id) - } else { - Ok("restored".into()) - } - } else { - Err("Restore command failed".into()) - } - } else { - Err("CANCELED".into()) - } -} - -pub fn ensure_server_list(instance_dir: &PathBuf, servers: Vec) { - let servers_db = instance_dir.join("servers.db"); - let mut all_servers = Vec::new(); - if let Ok(content) = fs::read(&servers_db) { - if content.len() >= 12 && &content[0..4] == b"MCSV" { - let count = u32::from_le_bytes(content[8..12].try_into().unwrap_or([0; 4])); - let mut pos = 12; - for _ in 0..count { - if pos + 2 > content.len() { break; } - let ip_len = u16::from_le_bytes(content[pos..pos+2].try_into().unwrap_or([0; 2])) as usize; - pos += 2; - if pos + ip_len > content.len() { break; } - let ip = String::from_utf8_lossy(&content[pos..pos+ip_len]).to_string(); - pos += ip_len; - if pos + 2 > content.len() { break; } - let port = u16::from_le_bytes(content[pos..pos+2].try_into().unwrap_or([0; 2])); - pos += 2; - if pos + 2 > content.len() { break; } - let name_len = u16::from_le_bytes(content[pos..pos+2].try_into().unwrap_or([0; 2])) as usize; - pos += 2; - if pos + name_len > content.len() { break; } - let name = String::from_utf8_lossy(&content[pos..pos+name_len]).to_string(); - pos += name_len; - all_servers.push(McServer { name, ip, port }); - } - } - } - - for s in servers { - all_servers.push(s); - } - - let mut unique_servers = Vec::new(); - let mut seen: std::collections::HashSet<(String, u16)> = std::collections::HashSet::new(); - for s in all_servers { - let key = (s.ip.clone(), s.port); - if seen.insert(key) { - unique_servers.push(s); - } - } - - let mut file_content = Vec::new(); - file_content.extend_from_slice(b"MCSV"); - file_content.extend_from_slice(&1u32.to_le_bytes()); - file_content.extend_from_slice(&(unique_servers.len() as u32).to_le_bytes()); - for server in unique_servers { - let ip_bytes = server.ip.as_bytes(); - let name_bytes = server.name.as_bytes(); - file_content.extend_from_slice(&(ip_bytes.len() as u16).to_le_bytes()); - file_content.extend_from_slice(ip_bytes); - file_content.extend_from_slice(&server.port.to_le_bytes()); - file_content.extend_from_slice(&(name_bytes.len() as u16).to_le_bytes()); - file_content.extend_from_slice(name_bytes); - } - let _ = fs::create_dir_all(instance_dir); - let _ = fs::write(&servers_db, file_content); -} - -fn perform_dlc_sync(app: &AppHandle, instance_dir: &PathBuf) -> Result<(), String> { - let mut dlc_src = None; - let root = util::get_app_dir(app); - use tauri::path::BaseDirectory; - if let Ok(p) = app.path().resolve("resources/DLC", BaseDirectory::Resource) { - if p.exists() { - dlc_src = Some(p); - } else { - if let Ok(p2) = app.path().resolve("DLC", BaseDirectory::Resource) { - if p2.exists() { dlc_src = Some(p2); } - } - } - } - - if dlc_src.is_none() { - let current = std::env::current_dir().unwrap_or_default(); - let p3 = current.join("src-tauri").join("resources").join("DLC"); - let p4 = current.join("resources").join("DLC"); - if p3.exists() { dlc_src = Some(p3); } - else if p4.exists() { dlc_src = Some(p4); } - } - - if dlc_src.is_none() { - let p5 = root.join("DLC"); - if p5.exists() { dlc_src = Some(p5); } - } - - match dlc_src { - Some(src) => { - let dlc_dest = instance_dir.join("Windows64Media").join("DLC"); - let _ = fs::create_dir_all(&dlc_dest); - if let Ok(entries) = fs::read_dir(&src) { - for entry in entries.flatten() { - let name = entry.file_name(); - let dest_path = dlc_dest.join(&name); - if !dest_path.exists() { - if let Err(e) = if entry.path().is_dir() { - util::copy_dir_all(entry.path(), &dest_path) - } else { - fs::copy(entry.path(), &dest_path).map(|_| ()) - } { - let _ = app.emit("backend-error", format!("DLC Sync: Failed to copy {:?}: {}", entry.path(), e)); - eprintln!("[DLC Sync] Failed to copy {:?} to {:?}: {}", entry.path(), dest_path, e); - } else { - println!("[DLC Sync] Copied to {:?}", dest_path); - } - } else { - println!("[DLC Sync] Skipping {:?}: Already exists in instance", name); - } - } - } - Ok(()) - }, - None => { - println!("[DLC Sync] Skipping sync: No DLC source found."); - Ok(()) - } - } -} - -fn apply_launch_prefix(program: &str, args: Vec, config: &AppConfig) -> (String, Vec) { - if let Some(ref prefix) = config.launch_prefix { - let trimmed = prefix.trim(); - if !trimmed.is_empty() { - let parts: Vec<&str> = trimmed.split_whitespace().collect(); - if !parts.is_empty() { - let mut all_args: Vec = parts[1..].iter().map(|s| s.to_string()).collect(); - all_args.push(program.to_string()); - all_args.extend(args); - return (parts[0].to_string(), all_args); - } - } - } - (program.to_string(), args) -} - -fn apply_launch_env_vars(cmd: &mut tokio::process::Command, config: &AppConfig) { - if let Some(ref env_vars) = config.launch_env_vars { - for (k, v) in env_vars { - cmd.env(k, v); - } - } -} - -const MAX_LOG_BYTES: usize = 1024 * 1024; -struct GameRunResult { - log: String, - exit_code: i32, -} - -fn spawn_log_reader(mut reader: R, log: Arc>>) -> tokio::task::JoinHandle<()> where R: AsyncRead + Unpin + Send + 'static, { - tokio::spawn(async move { - let mut buf = [0u8; 8192]; - loop { - match reader.read(&mut buf).await { - Ok(0) | Err(_) => break, - Ok(n) => { - let mut guard = log.lock().await; - guard.extend_from_slice(&buf[..n]); - if guard.len() > MAX_LOG_BYTES { - let remove = guard.len() - MAX_LOG_BYTES; - guard.drain(..remove); - } - } - } - } - }) -} - -async fn run_game_and_capture( - state: &State<'_, GameState>, - mut cmd: tokio::process::Command, -) -> Result, String> { - cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); - let mut child = cmd.spawn().map_err(|e| e.to_string())?; - let log = Arc::new(Mutex::new(Vec::new())); - let mut handles = Vec::new(); - if let Some(stdout) = child.stdout.take() { - handles.push(spawn_log_reader(stdout, log.clone())); - } - if let Some(stderr) = child.stderr.take() { - handles.push(spawn_log_reader(stderr, log.clone())); - } - { - let mut lock = state.child.lock().await; - *lock = Some(child); - } - let exit_code; - loop { - { - let mut lock = state.child.lock().await; - if let Some(ref mut c) = *lock { - if let Some(status) = c.try_wait().map_err(|e| e.to_string())? { - exit_code = status.code().unwrap_or(1); - break; - } - } else { - return Ok(None); - } - } - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - } - { - let mut lock = state.child.lock().await; - *lock = None; - } - for handle in handles { - let _ = handle.await; - } - let bytes = log.lock().await.clone(); - let log_str = String::from_utf8_lossy(&bytes).to_string(); - Ok(Some(GameRunResult { log: log_str, exit_code })) -} - -fn game_exited_ok(result: &GameRunResult) -> bool { - #[cfg(not(target_os = "windows"))] - { - result.log.lines() - .rev() - .take(3) - .any(|line| line.contains("AppPolicyGetProcessTerminationMethod")) - } - #[cfg(target_os = "windows")] - { - result.exit_code == 0 - } -} - -fn handle_game_exit( - app: &AppHandle, - state: &State<'_, GameState>, - result: GameRunResult, -) -> Result<(), String> { - if state.manual_stop.swap(false, Ordering::SeqCst) || game_exited_ok(&result) { - return Ok(()); - } - let _ = app.emit("game-log", result.log); - Err("The game exited unexpectedly. Check the crash log for details.".into()) -} - -async fn perform_instance_sync(app: &AppHandle, instance_id: &str) -> Result<(), String> { - let target_dir = util::get_instance_working_dir(app, instance_id); - if !target_dir.exists() { - return Err("Instance directory not found".into()); - } - - let config_val = config::load_config_raw(app.clone()); - let _ = fs::write(target_dir.join("username.txt"), &config_val.username); - let skin_pck_path = util::get_app_dir(app).join("Skin.pck"); - if skin_pck_path.exists() { - let skin_dlc_dir = target_dir.join("Windows64Media").join("DLC").join("Custom Skins"); - let _ = fs::create_dir_all(&skin_dlc_dir); - let _ = fs::copy(&skin_pck_path, skin_dlc_dir.join("Skin.pck")); - } - - perform_dlc_sync(app, &target_dir)?; - Ok(()) -} - -#[tauri::command] -#[cfg(target_os = "android")] -pub fn switch_proton(app: AppHandle, version: String) -> Result<(), String> { - let instance_id = { - let config_val = config::load_config_raw(app.clone()); - config_val.profile.unwrap_or_else(|| "legacy_evolved".into()) - }; - crate::android_runtime::launch_bridge( - instance_id, - crate::android_runtime::BridgeAction::SwitchProton, - vec![version], - ) -} - -#[tauri::command] -#[cfg(not(target_os = "android"))] -pub fn switch_proton(_app: AppHandle, _version: String) -> Result<(), String> { - Err("Only supported on Android".into()) -} - -#[tauri::command] -#[cfg(target_os = "android")] -pub fn install_latest_driver(app: AppHandle) -> Result<(), String> { - let instance_id = { - let config_val = config::load_config_raw(app.clone()); - config_val.profile.unwrap_or_else(|| "legacy_evolved".into()) - }; - crate::android_runtime::launch_bridge( - instance_id, - crate::android_runtime::BridgeAction::InstallDriver, - Vec::new(), - ) -} - -#[tauri::command] -#[cfg(not(target_os = "android"))] -pub fn install_latest_driver(_app: AppHandle) -> Result<(), String> { - Err("Only supported on Android".into()) -} - -#[tauri::command] -#[cfg(target_os = "android")] -pub fn set_audio_backend(app: AppHandle, backend: String) -> Result<(), String> { - let instance_id = { - let config_val = config::load_config_raw(app.clone()); - config_val.profile.unwrap_or_else(|| "legacy_evolved".into()) - }; - crate::android_runtime::launch_bridge( - instance_id, - crate::android_runtime::BridgeAction::SetAudioBackend, - vec![backend], - ) -} - -#[tauri::command] -#[cfg(not(target_os = "android"))] -pub fn set_audio_backend(_app: AppHandle, _backend: String) -> Result<(), String> { - Err("Only supported on Android".into()) -} diff --git a/src-tauri/src/commands/goldmapper.rs b/src-tauri/src/commands/goldmapper.rs deleted file mode 100644 index a928c3c..0000000 --- a/src-tauri/src/commands/goldmapper.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use tauri::{AppHandle, Manager}; -use crate::config; -use crate::types::{AppConfig, GoldMapperMapping}; -use crate::util; - -const CONTROLLER_TARGETS: [&str; 14] = [ - "PAD_A", - "PAD_B", - "PAD_X", - "PAD_Y", - "PAD_LB", - "PAD_RB", - "PAD_BACK", - "PAD_START", - "PAD_LTHUMB", - "PAD_RTHUMB", - "PAD_DPAD_UP", - "PAD_DPAD_DOWN", - "PAD_DPAD_LEFT", - "PAD_DPAD_RIGHT", -]; - -fn push_key(mappings: &mut Vec, name: String) { - mappings.push(GoldMapperMapping { - to: name.clone(), - from: name, - }); -} - -pub fn default_mappings() -> Vec { - let mut mappings = Vec::new(); - for b in b'A'..=b'Z' { - push_key(&mut mappings, format!("KEY_{}", b as char)); - } - for n in 0..=9 { - push_key(&mut mappings, format!("KEY_{n}")); - } - for f in 1..=12 { - push_key(&mut mappings, format!("KEY_F{f}")); - } - for k in [ - "KEY_SPACE", - "KEY_RETURN", - "KEY_ESCAPE", - "KEY_TAB", - "KEY_BACKSPACE", - "KEY_DELETE", - "KEY_INSERT", - "KEY_HOME", - "KEY_END", - "KEY_PAGEUP", - "KEY_PAGEDOWN", - "KEY_UP", - "KEY_DOWN", - "KEY_LEFT", - "KEY_RIGHT", - "KEY_PRINTSCREEN", - "KEY_PAUSE", - "KEY_CAPSLOCK", - "KEY_NUMLOCK", - "KEY_SCROLLLOCK", - "KEY_LSHIFT", - "KEY_RSHIFT", - "KEY_LCTRL", - "KEY_RCTRL", - "KEY_LALT", - "KEY_RALT", - "KEY_LWIN", - "KEY_RWIN", - "KEY_APPS", - ] { - push_key(&mut mappings, k.to_string()); - } - for n in 0..=9 { - push_key(&mut mappings, format!("KEY_NUMPAD{n}")); - } - for k in [ - "KEY_MULTIPLY", - "KEY_ADD", - "KEY_SUBTRACT", - "KEY_DECIMAL", - "KEY_DIVIDE", - "KEY_SEMICOLON", - "KEY_EQUALS", - "KEY_COMMA", - "KEY_MINUS", - "KEY_PERIOD", - "KEY_SLASH", - "KEY_GRAVE", - "KEY_LBRACKET", - "KEY_BACKSLASH", - "KEY_RBRACKET", - "KEY_APOSTROPHE", - ] { - push_key(&mut mappings, k.to_string()); - } - for m in ["MOUSE_LEFT", "MOUSE_RIGHT", "MOUSE_MIDDLE"] { - push_key(&mut mappings, m.to_string()); - } - for (i, target) in CONTROLLER_TARGETS.iter().enumerate() { - mappings.push(GoldMapperMapping { - from: format!("DINPUT_{i}"), - to: (*target).to_string(), - }); - } - mappings -} - -pub fn resolve_resource(app: &AppHandle, name: &str) -> Option { - use tauri::path::BaseDirectory; - if let Ok(p) = app.path().resolve(format!("resources/{name}"), BaseDirectory::Resource) { - if p.exists() { - return Some(p); - } - } - if let Ok(current) = std::env::current_dir() { - let p = current.join("src-tauri").join("resources").join(name); - if p.exists() { - return Some(p); - } - let p = current.join("resources").join(name); - if p.exists() { - return Some(p); - } - } - None -} - -pub fn write_runtime_config(app: &AppHandle, config_val: &AppConfig) -> Result { - let dir = util::get_app_dir(app).join("GoldMapper"); - fs::create_dir_all(&dir).map_err(|e| e.to_string())?; - let path = dir.join("config.json"); - let mappings = config_val - .goldmapper_mappings - .clone() - .unwrap_or_else(default_mappings); - let json = serde_json::to_string(&serde_json::json!({ "mappings": mappings })) - .map_err(|e| e.to_string())?; - fs::write(&path, json).map_err(|e| e.to_string())?; - Ok(path) -} - -pub fn build_launch_args( - app: &AppHandle, - config_val: &AppConfig, - game_exe: &PathBuf, - extra_args: &[String], -) -> Result>, String> { - if !config_val.goldmapper_enabled.unwrap_or(true) { - return Ok(None); - } - let launcher = - resolve_resource(app, "GoldMapperLauncher.exe").ok_or_else(|| "GoldMapperLauncher.exe not found in resources".to_string())?; - let config_path = write_runtime_config(app, config_val)?; - #[cfg(windows)] - { - let mut args = vec![ - launcher.to_string_lossy().to_string(), - config_path.to_string_lossy().to_string(), - game_exe.to_string_lossy().to_string(), - ]; - args.extend(extra_args.iter().cloned()); - Ok(Some(args)) - } - #[cfg(unix)] - { - let mut args = vec![ - util::unix_path_to_wine_z_path(&launcher), - util::unix_path_to_wine_z_path(&config_path), - util::unix_path_to_wine_z_path(game_exe), - ]; - args.extend(extra_args.iter().cloned()); - Ok(Some(args)) - } -} - -#[tauri::command] -pub fn goldmapper_get_defaults() -> Vec { - default_mappings() -} - -#[tauri::command] -pub fn goldmapper_load_config(app: AppHandle) -> Vec { - config::load_config_raw(app.clone()) - .goldmapper_mappings - .unwrap_or_else(default_mappings) -} - -#[tauri::command] -pub fn goldmapper_save_config( - app: AppHandle, - mappings: Vec, -) -> Result<(), String> { - let mut config_val = config::load_config_raw(app.clone()); - config_val.goldmapper_mappings = Some(mappings); - println!( - "[GoldMapper] config saved: {}", - serde_json::json!({ "mappings": config_val.goldmapper_mappings }) - ); - config::save_config_raw(&app, &config_val); - Ok(()) -} - -#[tauri::command] -pub fn goldmapper_reset_config(app: AppHandle) -> Vec { - let mut config_val = config::load_config_raw(app.clone()); - config_val.goldmapper_mappings = None; - config::save_config_raw(&app, &config_val); - default_mappings() -} diff --git a/src-tauri/src/commands/java2lce/block_mapping.rs b/src-tauri/src/commands/java2lce/block_mapping.rs deleted file mode 100644 index 0de2b71..0000000 --- a/src-tauri/src/commands/java2lce/block_mapping.rs +++ /dev/null @@ -1,1355 +0,0 @@ -use std::collections::HashMap; -use super::nbt::NbtCompound; -#[derive(Clone, Copy, Default)] -pub struct LegacyBlockState { - pub id: u8, - pub data: u8, -} - -pub fn map_modern_block_state(compound: &NbtCompound) -> LegacyBlockState { - map_modern_block_state_inner(compound, None) -} -/* -//neo: unused -pub fn map_modern_block_state_with_context( - compound: &NbtCompound, - unknown_blocks: Option<&mut Vec>, -) -> LegacyBlockState { - map_modern_block_state_inner(compound, unknown_blocks) -} -*/ -fn map_modern_block_state_inner( - compound: &NbtCompound, - mut unknown_blocks: Option<&mut Vec>, -) -> LegacyBlockState { - let name_raw = compound.string("Name").unwrap_or("minecraft:air"); - let name = name_raw.strip_prefix("minecraft:").unwrap_or(name_raw); - let properties = compound.compound("Properties"); - if let Some(fluid) = try_map_fluid(name, properties) { - return fluid; - } - if let Some(slab) = try_map_slab(name, properties) { - return slab; - } - if let Some(directional) = try_map_directional(name, properties) { - return directional; - } - if let Some(flattened) = try_map_flattened_colored(name) { - return flattened; - } - if let Some(direct) = MODERN_DIRECT_MAP.get(name) { - return *direct; - } - if let Some(colored) = try_map_colored(name, properties) { - return colored; - } - if let Some(wood) = try_map_wood(name, properties) { - return wood; - } - if let Some(variant) = try_map_variant(name, properties) { - return variant; - } - - if let Some(ref mut blocks) = unknown_blocks { - if !name.is_empty() && name != "air" && name != "cave_air" && name != "void_air" { - blocks.push(name.to_string()); - } - } - - LegacyBlockState { id: 0, data: 0 } -} - -fn get_property<'a>(properties: Option<&'a NbtCompound>, name: &str) -> String { - properties - .and_then(|p| p.string(name)) - .unwrap_or("") - .to_string() -} - -fn get_bool_property(properties: Option<&NbtCompound>, name: &str) -> bool { - get_property(properties, name).to_lowercase() == "true" -} - -fn get_int_property(properties: Option<&NbtCompound>, name: &str, default: i32) -> i32 { - get_property(properties, name) - .parse() - .unwrap_or(default) -} - -fn try_map_fluid(name: &str, properties: Option<&NbtCompound>) -> Option { - if name != "water" && name != "lava" { - return None; - } - let level = get_int_property(properties, "level", 0).clamp(0, 15); - let is_source = level == 0; - let data = level as u8; - Some(if name == "water" { - LegacyBlockState { - id: if is_source { 9 } else { 8 }, - data, - } - } else { - LegacyBlockState { - id: if is_source { 11 } else { 10 }, - data, - } - }) -} - -fn try_map_directional(name: &str, properties: Option<&NbtCompound>) -> Option { - match name { - "ladder" => Some(LegacyBlockState { - id: 65, - data: map_ladder_facing(&get_property(properties, "facing")), - }), - "vine" => Some(LegacyBlockState { - id: 106, - data: map_vine_faces(properties), - }), - "lever" => { - let mut data = - map_lever_data(&get_property(properties, "face"), &get_property(properties, "facing")); - if get_bool_property(properties, "powered") { - data |= 8; - } - Some(LegacyBlockState { id: 69, data }) - } - _ if name.ends_with("_button") => { - let id = if is_wood_family(name) { 143 } else { 77 }; - let mut data = map_button_facing(&get_property(properties, "facing")); - if get_bool_property(properties, "powered") { - data |= 8; - } - Some(LegacyBlockState { id, data }) - } - _ if name.ends_with("_fence_gate") => { - let mut data = map_fence_gate_facing(&get_property(properties, "facing")); - if get_bool_property(properties, "open") { - data |= 4; - } - Some(LegacyBlockState { id: 107, data }) - } - _ if name.ends_with("_pressure_plate") => { - let id = match name { - "light_weighted_pressure_plate" => 147, - "heavy_weighted_pressure_plate" => 148, - _ if is_wood_family(name) => 72, - _ => 70, - }; - let powered = - get_bool_property(properties, "powered") || get_int_property(properties, "power", 0) > 0; - Some(LegacyBlockState { - id, - data: if powered { 1 } else { 0 }, - }) - } - _ if name.ends_with("_door") || name == "iron_door" => { - let id = if name == "iron_door" { 71 } else { 64 }; - let half = get_property(properties, "half"); - let is_upper = half == "upper"; - if is_upper { - let mut data = 8; - if get_property(properties, "hinge") == "right" { - data |= 1; - } - if get_bool_property(properties, "powered") { - data |= 2; - } - Some(LegacyBlockState { id, data }) - } else { - let mut data = map_door_facing(&get_property(properties, "facing")); - if get_bool_property(properties, "open") { - data |= 4; - } - Some(LegacyBlockState { id, data }) - } - } - _ if try_get_stairs_id(name).is_some() => { - let id = try_get_stairs_id(name).unwrap(); - let mut data = map_stairs_facing(&get_property(properties, "facing")); - if get_property(properties, "half") == "top" { - data |= 4; - } - Some(LegacyBlockState { id, data }) - } - _ if name.ends_with("trapdoor") => { - let mut data = map_trapdoor_facing(&get_property(properties, "facing")); - if get_bool_property(properties, "open") { - data |= 4; - } - if get_property(properties, "half") == "top" { - data |= 8; - } - Some(LegacyBlockState { id: 96, data }) - } - "dispenser" | "dropper" => { - let id = if name == "dropper" { 158 } else { 23 }; - let mut data = map_facing_data(&get_property(properties, "facing")); - if get_bool_property(properties, "triggered") { - data |= 8; - } - Some(LegacyBlockState { id, data }) - } - "piston" | "sticky_piston" => { - let id = if name == "sticky_piston" { 29 } else { 33 }; - let mut data = map_facing_data(&get_property(properties, "facing")); - if get_bool_property(properties, "extended") { - data |= 8; - } - Some(LegacyBlockState { id, data }) - } - "piston_head" => { - let mut data = map_facing_data(&get_property(properties, "facing")); - if get_property(properties, "type") == "sticky" { - data |= 8; - } - Some(LegacyBlockState { id: 34, data }) - } - "redstone_wire" => { - let data = get_int_property(properties, "power", 0).clamp(0, 15) as u8; - Some(LegacyBlockState { id: 55, data }) - } - "repeater" => { - let id = if get_bool_property(properties, "powered") { 94 } else { 93 }; - let dir = map_repeater_direction(&get_property(properties, "facing")); - let delay = get_int_property(properties, "delay", 1).clamp(1, 4); - Some(LegacyBlockState { - id, - data: dir | (((delay - 1) as u8) << 2), - }) - } - "comparator" => { - let id = if get_bool_property(properties, "powered") { 150 } else { 149 }; - let dir = map_repeater_direction(&get_property(properties, "facing")); - let mode = if get_property(properties, "mode") == "subtract" { 4 } else { 0 }; - Some(LegacyBlockState { - id, - data: dir | mode, - }) - } - "wall_torch" => Some(LegacyBlockState { - id: 50, - data: map_wall_torch_facing(&get_property(properties, "facing")), - }), - "redstone_wall_torch" => { - let id = if get_bool_property(properties, "lit") { 76 } else { 75 }; - Some(LegacyBlockState { - id, - data: map_wall_torch_facing(&get_property(properties, "facing")), - }) - } - "nether_wart" => Some(LegacyBlockState { - id: 115, - data: get_int_property(properties, "age", 0).clamp(0, 3) as u8, - }), - "wheat" => Some(LegacyBlockState { - id: 59, - data: get_int_property(properties, "age", 0).clamp(0, 7) as u8, - }), - "pumpkin_stem" | "attached_pumpkin_stem" => Some(LegacyBlockState { - id: 104, - data: if name == "attached_pumpkin_stem" { - 7 - } else { - get_int_property(properties, "age", 0).clamp(0, 7) as u8 - }, - }), - "melon_stem" | "attached_melon_stem" => Some(LegacyBlockState { - id: 105, - data: if name == "attached_melon_stem" { - 7 - } else { - get_int_property(properties, "age", 0).clamp(0, 7) as u8 - }, - }), - "cocoa" => { - let age = get_int_property(properties, "age", 0).clamp(0, 2) as u8; - let dir = map_repeater_direction(&get_property(properties, "facing")); - Some(LegacyBlockState { - id: 127, - data: (age << 2) | dir, - }) - } - "hay_block" => Some(LegacyBlockState { - id: 170, - data: match get_property(properties, "axis").as_str() { - "x" => 4, - "z" => 8, - _ => 0, - }, - }), - "quartz_pillar" => Some(LegacyBlockState { - id: 155, - data: match get_property(properties, "axis").as_str() { - "x" => 3, - "z" => 4, - _ => 2, - }, - }), - "nether_portal" => Some(LegacyBlockState { - id: 90, - data: if get_property(properties, "axis") == "z" { 2 } else { 1 }, - }), - _ => None, - } -} - -fn try_map_slab(name: &str, properties: Option<&NbtCompound>) -> Option { - if !name.ends_with("_slab") { - return None; - } - - let slab_type = get_property(properties, "type"); - let is_top = slab_type == "top"; - let is_double = slab_type == "double"; - if let Some(wood_variant) = get_wood_slab_variant(name) { - return Some(if is_double { - LegacyBlockState { - id: 125, - data: wood_variant, - } - } else { - LegacyBlockState { - id: 126, - data: wood_variant | if is_top { 8 } else { 0 }, - } - }); - } - - if let Some(slab_variant) = get_stone_slab_variant(name) { - return Some(if is_double { - LegacyBlockState { - id: 43, - data: slab_variant, - } - } else { - LegacyBlockState { - id: 44, - data: slab_variant | if is_top { 8 } else { 0 }, - } - }); - } - - Some(if is_double { - LegacyBlockState { id: 43, data: 0 } - } else { - LegacyBlockState { - id: 44, - data: if is_top { 8 } else { 0 }, - } - }) -} - -fn get_wood_slab_variant(name: &str) -> Option { - match name { - "oak_slab" => Some(0), - "spruce_slab" => Some(1), - "birch_slab" => Some(2), - "jungle_slab" => Some(3), - "acacia_slab" => Some(4), - "dark_oak_slab" => Some(5), - _ => None, - } -} - -fn get_stone_slab_variant(name: &str) -> Option { - match name { - "stone_slab" | "smooth_stone_slab" | "andesite_slab" | "polished_andesite_slab" - | "diorite_slab" | "polished_diorite_slab" | "granite_slab" | "polished_granite_slab" => { - Some(0) - } - "sandstone_slab" | "smooth_sandstone_slab" | "cut_sandstone_slab" - | "red_sandstone_slab" | "smooth_red_sandstone_slab" | "cut_red_sandstone_slab" => Some(1), - "cobblestone_slab" | "mossy_cobblestone_slab" | "cobbled_deepslate_slab" - | "deepslate_brick_slab" | "deepslate_tile_slab" => Some(3), - "brick_slab" => Some(4), - "stone_brick_slab" | "mossy_stone_brick_slab" => Some(5), - "nether_brick_slab" | "red_nether_brick_slab" => Some(6), - "quartz_slab" | "smooth_quartz_slab" | "purpur_slab" | "prismarine_slab" - | "prismarine_brick_slab" | "dark_prismarine_slab" => Some(7), - _ => None, - } -} - -fn try_get_stairs_id(name: &str) -> Option { - match name { - "oak_stairs" | "spruce_stairs" | "birch_stairs" | "jungle_stairs" | "acacia_stairs" - | "dark_oak_stairs" => Some(53), - "cobblestone_stairs" | "stone_stairs" | "mossy_cobblestone_stairs" - | "cobbled_deepslate_stairs" | "blackstone_stairs" => Some(67), - "brick_stairs" => Some(108), - "stone_brick_stairs" | "dark_prismarine_stairs" | "prismarine_stairs" - | "prismarine_brick_stairs" | "polished_blackstone_brick_stairs" - | "mossy_stone_brick_stairs" | "deepslate_brick_stairs" | "deepslate_tile_stairs" => { - Some(109) - } - "nether_brick_stairs" | "crimson_stairs" | "warped_stairs" => Some(114), - "sandstone_stairs" | "red_sandstone_stairs" => Some(128), - "quartz_stairs" | "purpur_stairs" => Some(156), - "spruce_stairs" => Some(134), - "birch_stairs" => Some(135), - "jungle_stairs" => Some(136), - "acacia_stairs" => Some(163), - "dark_oak_stairs" => Some(164), - _ => None, - } -} - -fn map_stairs_facing(facing: &str) -> u8 { - match facing { - "east" => 0, - "west" => 1, - "south" => 2, - "north" => 3, - _ => 0, - } -} - -fn map_ladder_facing(facing: &str) -> u8 { - match facing { - "north" => 2, - "south" => 3, - "west" => 4, - "east" => 5, - _ => 2, - } -} - -fn map_button_facing(facing: &str) -> u8 { - match facing { - "east" => 1, - "west" => 2, - "south" => 3, - "north" => 4, - _ => 1, - } -} - -fn map_fence_gate_facing(facing: &str) -> u8 { - match facing { - "south" => 0, - "west" => 1, - "north" => 2, - "east" => 3, - _ => 0, - } -} - -fn map_vine_faces(properties: Option<&NbtCompound>) -> u8 { - let mut data = 0; - if get_bool_property(properties, "south") { - data |= 1; - } - if get_bool_property(properties, "west") { - data |= 2; - } - if get_bool_property(properties, "north") { - data |= 4; - } - if get_bool_property(properties, "east") { - data |= 8; - } - data -} - -fn map_lever_data(face: &str, facing: &str) -> u8 { - match face { - "floor" => { - if facing == "east" || facing == "west" { - 6 - } else { - 5 - } - } - "ceiling" => { - if facing == "east" || facing == "west" { - 7 - } else { - 0 - } - } - _ => map_button_facing(facing), - } -} - -fn map_door_facing(facing: &str) -> u8 { - match facing { - "east" => 0, - "south" => 1, - "west" => 2, - "north" => 3, - _ => 0, - } -} - -fn map_trapdoor_facing(facing: &str) -> u8 { - match facing { - "north" => 0, - "south" => 1, - "west" => 2, - "east" => 3, - _ => 0, - } -} - -fn map_facing_data(facing: &str) -> u8 { - match facing { - "down" => 0, - "up" => 1, - "north" => 2, - "south" => 3, - "west" => 4, - "east" => 5, - _ => 3, - } -} - -fn map_repeater_direction(facing: &str) -> u8 { - match facing { - "south" => 0, - "west" => 1, - "north" => 2, - "east" => 3, - _ => 0, - } -} - -fn map_wall_torch_facing(facing: &str) -> u8 { - match facing { - "east" => 1, - "west" => 2, - "south" => 3, - "north" => 4, - _ => 1, - } -} - -fn try_map_colored(name: &str, properties: Option<&NbtCompound>) -> Option { - let color = get_color_data(&get_property(properties, "color")); - match name { - "wool" => Some(LegacyBlockState { id: 35, data: color }), - "stained_glass" => Some(LegacyBlockState { id: 95, data: color }), - "stained_glass_pane" => Some(LegacyBlockState { id: 160, data: color }), - "stained_hardened_clay" | "terracotta" => { - Some(LegacyBlockState { id: 159, data: color }) - } - "concrete" => Some(LegacyBlockState { - id: 172, - data: color, - }), - "concrete_powder" => Some(LegacyBlockState { id: 12, data: color }), - "glazed_terracotta" => Some(LegacyBlockState { id: 159, data: color }), - _ => None, - } -} - -fn try_map_flattened_colored(name: &str) -> Option { - let (color_data, suffix) = split_color_prefix(name)?; - let data = color_data; - match suffix.as_str() { - "wool" => Some(LegacyBlockState { id: 35, data }), - "stained_glass" | "glass" => Some(LegacyBlockState { id: 95, data }), - "stained_glass_pane" | "glass_pane" => Some(LegacyBlockState { id: 160, data }), - "stained_hardened_clay" | "terracotta" => Some(LegacyBlockState { id: 159, data }), - "concrete" => Some(LegacyBlockState { id: 172, data }), - "concrete_powder" => Some(LegacyBlockState { id: 12, data }), - "glazed_terracotta" => Some(LegacyBlockState { id: 159, data }), - "carpet" => Some(LegacyBlockState { id: 171, data }), - _ => None, - } -} - -fn split_color_prefix(name: &str) -> Option<(u8, String)> { - for color_name in COLOR_NAMES { - let prefix = format!("{}_", color_name); - if name.starts_with(&prefix) { - let suffix = name[prefix.len()..].to_string(); - return Some((get_color_data(color_name), suffix)); - } - } - None -} - -const COLOR_NAMES: &[&str] = &[ - "white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "silver", - "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black", -]; - -fn get_color_data(color: &str) -> u8 { - match color { - "white" => 0, - "orange" => 1, - "magenta" => 2, - "light_blue" => 3, - "yellow" => 4, - "lime" => 5, - "pink" => 6, - "gray" => 7, - "light_gray" => 8, - "cyan" => 9, - "purple" => 10, - "blue" => 11, - "brown" => 12, - "green" => 13, - "red" => 14, - "black" => 15, - _ => 0, - } -} - -fn try_map_wood(name: &str, properties: Option<&NbtCompound>) -> Option { - let wood_type = get_property(properties, "variant"); - let wood_type = if wood_type.is_empty() { - get_prefix_before_underscore(name) - } else { - wood_type - }; - - let data_value = match wood_type.as_str() { - "spruce" => 1, - "birch" => 2, - "jungle" => 3, - "acacia" => 0, - "dark_oak" => 1, - _ => 0, - }; - - if name.ends_with("_planks") || name == "planks" { - return Some(LegacyBlockState { id: 5, data: data_value }); - } - if name.ends_with("_sapling") || name == "sapling" { - return Some(LegacyBlockState { id: 6, data: data_value }); - } - if name.ends_with("_log") || name == "log" { - return Some(LegacyBlockState { - id: 17, - data: data_value.min(3), - }); - } - if name.ends_with("_leaves") || name == "leaves" { - return Some(LegacyBlockState { - id: 18, - data: data_value.min(3), - }); - } - if name.ends_with("_stairs") && name.contains("wood") { - return Some(LegacyBlockState { id: 53, data: 0 }); - } - if name.ends_with("_door") { - return Some(LegacyBlockState { id: 64, data: 0 }); - } - if name.ends_with("_fence") { - return Some(LegacyBlockState { id: 85, data: 0 }); - } - if name.ends_with("_fence_gate") { - return Some(LegacyBlockState { id: 107, data: 0 }); - } - if name.ends_with("_pressure_plate") && is_wood_family(name) { - return Some(LegacyBlockState { id: 72, data: 0 }); - } - - None -} - -fn try_map_variant(name: &str, properties: Option<&NbtCompound>) -> Option { - if let Some(fallback) = try_map_common_fallback(name, properties) { - return Some(fallback); - } - - if name == "redstone_lamp" { - let lit = get_bool_property(properties, "lit"); - return Some(LegacyBlockState { - id: if lit { 124 } else { 123 }, - data: 0, - }); - } - - let result = match name { - "deepslate" | "polished_deepslate" | "tuff" | "calcite" | "dripstone_block" => { - Some(LegacyBlockState { id: 1, data: 0 }) - } - "cobbled_deepslate" => Some(LegacyBlockState { id: 4, data: 0 }), - "deepslate_bricks" | "deepslate_tiles" => Some(LegacyBlockState { id: 98, data: 0 }), - "cracked_deepslate_bricks" | "cracked_deepslate_tiles" => { - Some(LegacyBlockState { id: 98, data: 2 }) - } - "chiseled_deepslate" => Some(LegacyBlockState { id: 98, data: 3 }), - "deepslate_coal_ore" => Some(LegacyBlockState { id: 16, data: 0 }), - "deepslate_iron_ore" | "deepslate_copper_ore" => { - Some(LegacyBlockState { id: 15, data: 0 }) - } - "deepslate_gold_ore" => Some(LegacyBlockState { id: 14, data: 0 }), - "deepslate_redstone_ore" => Some(LegacyBlockState { id: 73, data: 0 }), - "deepslate_lapis_ore" => Some(LegacyBlockState { id: 21, data: 0 }), - "deepslate_diamond_ore" => Some(LegacyBlockState { id: 56, data: 0 }), - "deepslate_emerald_ore" => Some(LegacyBlockState { id: 129, data: 0 }), - "deepslate_tile_stairs" | "deepslate_brick_stairs" | "cobbled_deepslate_stairs" => { - Some(LegacyBlockState { id: 67, data: 0 }) - } - "deepslate_tile_slab" | "deepslate_brick_slab" | "cobbled_deepslate_slab" => { - Some(LegacyBlockState { id: 44, data: 3 }) - } - "deepslate_tile_wall" | "deepslate_brick_wall" | "cobbled_deepslate_wall" => { - Some(LegacyBlockState { id: 139, data: 0 }) - } - "grass_block" => Some(LegacyBlockState { id: 2, data: 0 }), - "coarse_dirt" | "podzol" => Some(LegacyBlockState { id: 3, data: 0 }), - "grass_path" | "dirt_path" | "moss_carpet" => Some(LegacyBlockState { id: 2, data: 0 }), - "cobblestone_wall" => Some(LegacyBlockState { id: 139, data: 0 }), - "mossy_cobblestone_wall" => Some(LegacyBlockState { id: 139, data: 1 }), - "smooth_stone_slab" => Some(LegacyBlockState { id: 44, data: 0 }), - "stone_brick_stairs" => Some(LegacyBlockState { id: 109, data: 0 }), - "mossy_stone_bricks" => Some(LegacyBlockState { id: 98, data: 1 }), - "cracked_stone_bricks" => Some(LegacyBlockState { id: 98, data: 2 }), - "chiseled_stone_bricks" => Some(LegacyBlockState { id: 98, data: 3 }), - "red_sand" => Some(LegacyBlockState { id: 12, data: 1 }), - "red_sandstone" => Some(LegacyBlockState { id: 24, data: 0 }), - "smooth_sandstone" => Some(LegacyBlockState { id: 24, data: 2 }), - "chiseled_sandstone" | "cut_sandstone" => Some(LegacyBlockState { id: 24, data: 1 }), - "smooth_red_sandstone" | "chiseled_red_sandstone" | "cut_red_sandstone" => { - Some(LegacyBlockState { id: 24, data: 0 }) - } - "red_sandstone_stairs" => Some(LegacyBlockState { id: 128, data: 0 }), - "red_sandstone_slab" => Some(LegacyBlockState { id: 44, data: 1 }), - "prismarine" | "prismarine_bricks" | "dark_prismarine" => { - Some(LegacyBlockState { id: 1, data: 0 }) - } - "sea_lantern" => Some(LegacyBlockState { id: 89, data: 0 }), - "purpur_block" | "purpur_pillar" => Some(LegacyBlockState { id: 155, data: 0 }), - "purpur_stairs" => Some(LegacyBlockState { id: 156, data: 0 }), - "purpur_slab" => Some(LegacyBlockState { id: 44, data: 0 }), - "end_stone_bricks" => Some(LegacyBlockState { id: 121, data: 0 }), - "magma_block" => Some(LegacyBlockState { id: 87, data: 0 }), - "nether_wart_block" | "red_nether_bricks" => Some(LegacyBlockState { id: 112, data: 0 }), - "bone_block" => Some(LegacyBlockState { id: 1, data: 0 }), - "packed_ice" | "blue_ice" => Some(LegacyBlockState { id: 79, data: 0 }), - "observer" | "beetroots" | "kelp" | "kelp_plant" | "seagrass" | "tall_seagrass" - | "coral_block" | "tube_coral_block" | "brain_coral_block" | "bubble_coral_block" - | "fire_coral_block" | "horn_coral_block" | "end_rod" | "chorus_plant" - | "chorus_flower" | "end_gateway" | "structure_void" => { - Some(LegacyBlockState { id: 0, data: 0 }) - } - "sunflower" | "lilac" | "rose_bush" | "peony" => { - if get_property(properties, "half") == "upper" { - Some(LegacyBlockState { id: 0, data: 0 }) - } else { - Some(LegacyBlockState { id: 38, data: 0 }) - } - } - "tall_grass" => { - if get_property(properties, "half") == "upper" { - Some(LegacyBlockState { id: 0, data: 0 }) - } else { - let grass_type = get_property(properties, "type"); - Some(LegacyBlockState { - id: 31, - data: if grass_type == "fern" { 2 } else { 1 }, - }) - } - } - "large_fern" => { - if get_property(properties, "half") == "upper" { - Some(LegacyBlockState { id: 0, data: 0 }) - } else { - Some(LegacyBlockState { id: 31, data: 2 }) - } - } - "stone" => { - let _type = get_property(properties, "type"); - Some(LegacyBlockState { id: 1, data: 0 }) - } - "sandstone" => { - let stype = get_property(properties, "type"); - Some(LegacyBlockState { - id: 24, - data: match stype.as_str() { - "chiseled" => 1, - "smooth" => 2, - _ => 0, - }, - }) - } - "stone_bricks" => { - let stype = get_property(properties, "type"); - Some(LegacyBlockState { - id: 98, - data: match stype.as_str() { - "mossy" => 1, - "cracked" => 2, - "chiseled" => 3, - _ => 0, - }, - }) - } - _ => None, - }; - - result -} - -fn try_map_common_fallback(name: &str, properties: Option<&NbtCompound>) -> Option { - if name.ends_with("_button") { - return Some(LegacyBlockState { - id: if is_wood_family(name) { 143 } else { 77 }, - data: 0, - }); - } - if name.ends_with("_wall_sign") { - return Some(LegacyBlockState { - id: 68, - data: map_wall_sign_facing(&get_property(properties, "facing")), - }); - } - if name.ends_with("_sign") { - return Some(LegacyBlockState { - id: 63, - data: (get_int_property(properties, "rotation", 0) & 0x0F) as u8, - }); - } - if name.ends_with("_wall") { - return Some(LegacyBlockState { id: 139, data: 0 }); - } - if name.ends_with("_bed") { - let mut data = map_bed_facing(&get_property(properties, "facing")); - if get_property(properties, "part") == "head" { - data |= 8; - } - return Some(LegacyBlockState { id: 26, data }); - } - if name.ends_with("_banner") { - return Some(LegacyBlockState { id: 0, data: 0 }); - } - - match name { - "barrier" | "structure_void" => Some(LegacyBlockState { id: 0, data: 0 }), - "bamboo" => Some(LegacyBlockState { id: 83, data: 0 }), - "cake" => Some(LegacyBlockState { id: 92, data: 0 }), - "brewing_stand" => Some(LegacyBlockState { id: 117, data: 0 }), - "barrel" => Some(LegacyBlockState { id: 54, data: 0 }), - "blast_furnace" => Some(LegacyBlockState { id: 61, data: 0 }), - "campfire" => Some(LegacyBlockState { id: 50, data: 0 }), - "azure_bluet" | "blue_orchid" => Some(LegacyBlockState { id: 38, data: 0 }), - "attached_melon_stem" => Some(LegacyBlockState { id: 105, data: 7 }), - "attached_pumpkin_stem" => Some(LegacyBlockState { id: 104, data: 7 }), - "andesite" | "diorite" | "granite" | "polished_andesite" | "polished_diorite" - | "polished_granite" => Some(LegacyBlockState { id: 1, data: 0 }), - "andesite_stairs" | "diorite_stairs" | "granite_stairs" | "polished_andesite_stairs" - | "polished_diorite_stairs" | "polished_granite_stairs" => { - Some(LegacyBlockState { id: 109, data: 0 }) - } - "bubble_column" => Some(LegacyBlockState { id: 9, data: 0 }), - "amethyst_block" | "budding_amethyst" | "amethyst_cluster" => { - Some(LegacyBlockState { id: 20, data: 0 }) - } - _ => None, - } -} - -fn map_bed_facing(facing: &str) -> u8 { - match facing { - "south" => 0, - "west" => 1, - "north" => 2, - "east" => 3, - _ => 0, - } -} - -fn map_wall_sign_facing(facing: &str) -> u8 { - match facing { - "north" => 2, - "south" => 3, - "west" => 4, - "east" => 5, - _ => 2, - } -} - -fn get_prefix_before_underscore(value: &str) -> String { - let index = value.find('_'); - match index { - Some(i) if i > 0 => value[..i].to_string(), - _ => value.to_string(), - } -} - -fn is_wood_family(name: &str) -> bool { - name.contains("oak") - || name.contains("spruce") - || name.contains("birch") - || name.contains("jungle") - || name.contains("acacia") - || name.contains("dark_oak") - || name.contains("mangrove") - || name.contains("cherry") - || name.contains("bamboo") - || name.contains("crimson") - || name.contains("warped") -} - -pub fn is_valid_lce_tile_id(id: u8) -> bool { - id <= 160 || (id >= 170 && id <= 173) -} - -pub fn remap_blocks(blocks: &mut [u8], _data: &mut [u8]) { - for id in blocks.iter_mut() { - let mut bid = *id; - if bid == 137 { - bid = 1; - } - if bid >= 165 { - if let Some(&replacement) = BLOCK_REMAP_TABLE.get(&bid) { - bid = replacement; - } - } - if !is_valid_lce_tile_id(bid) { - bid = 0; - } - *id = bid; - } -} - -static MODERN_DIRECT_MAP: once_cell::sync::Lazy> = - once_cell::sync::Lazy::new(|| { - let mut m = HashMap::new(); - m.insert("air", LegacyBlockState { id: 0, data: 0 }); - m.insert("cave_air", LegacyBlockState { id: 0, data: 0 }); - m.insert("void_air", LegacyBlockState { id: 0, data: 0 }); - m.insert("stone", LegacyBlockState { id: 1, data: 0 }); - m.insert("grass", LegacyBlockState { id: 31, data: 1 }); - m.insert("short_grass", LegacyBlockState { id: 31, data: 1 }); - m.insert("short_dry_grass", LegacyBlockState { id: 31, data: 1 }); - m.insert("dirt", LegacyBlockState { id: 3, data: 0 }); - m.insert("cobblestone", LegacyBlockState { id: 4, data: 0 }); - m.insert("bedrock", LegacyBlockState { id: 7, data: 0 }); - m.insert("water", LegacyBlockState { id: 8, data: 0 }); - m.insert("lava", LegacyBlockState { id: 10, data: 0 }); - m.insert("sand", LegacyBlockState { id: 12, data: 0 }); - m.insert("gravel", LegacyBlockState { id: 13, data: 0 }); - m.insert("gold_ore", LegacyBlockState { id: 14, data: 0 }); - m.insert("iron_ore", LegacyBlockState { id: 15, data: 0 }); - m.insert("coal_ore", LegacyBlockState { id: 16, data: 0 }); - m.insert("oak_log", LegacyBlockState { id: 17, data: 0 }); - m.insert("oak_leaves", LegacyBlockState { id: 18, data: 0 }); - m.insert("glass", LegacyBlockState { id: 20, data: 0 }); - m.insert("lapis_ore", LegacyBlockState { id: 21, data: 0 }); - m.insert("lapis_block", LegacyBlockState { id: 22, data: 0 }); - m.insert("dispenser", LegacyBlockState { id: 23, data: 0 }); - m.insert("sandstone", LegacyBlockState { id: 24, data: 0 }); - m.insert("note_block", LegacyBlockState { id: 25, data: 0 }); - m.insert("powered_rail", LegacyBlockState { id: 27, data: 0 }); - m.insert("detector_rail", LegacyBlockState { id: 28, data: 0 }); - m.insert("sticky_piston", LegacyBlockState { id: 29, data: 0 }); - m.insert("cobweb", LegacyBlockState { id: 30, data: 0 }); - m.insert("dead_bush", LegacyBlockState { id: 32, data: 0 }); - m.insert("piston", LegacyBlockState { id: 33, data: 0 }); - m.insert("wool", LegacyBlockState { id: 35, data: 0 }); - m.insert("dandelion", LegacyBlockState { id: 37, data: 0 }); - m.insert("poppy", LegacyBlockState { id: 38, data: 0 }); - m.insert("brown_mushroom", LegacyBlockState { id: 39, data: 0 }); - m.insert("red_mushroom", LegacyBlockState { id: 40, data: 0 }); - m.insert("gold_block", LegacyBlockState { id: 41, data: 0 }); - m.insert("iron_block", LegacyBlockState { id: 42, data: 0 }); - m.insert("stone_slab", LegacyBlockState { id: 44, data: 0 }); - m.insert("bricks", LegacyBlockState { id: 45, data: 0 }); - m.insert("tnt", LegacyBlockState { id: 46, data: 0 }); - m.insert("bookshelf", LegacyBlockState { id: 47, data: 0 }); - m.insert("mossy_cobblestone", LegacyBlockState { id: 48, data: 0 }); - m.insert("obsidian", LegacyBlockState { id: 49, data: 0 }); - m.insert("torch", LegacyBlockState { id: 50, data: 0 }); - m.insert("fire", LegacyBlockState { id: 51, data: 0 }); - m.insert("mob_spawner", LegacyBlockState { id: 52, data: 0 }); - m.insert("oak_stairs", LegacyBlockState { id: 53, data: 0 }); - m.insert("chest", LegacyBlockState { id: 54, data: 0 }); - m.insert("diamond_ore", LegacyBlockState { id: 56, data: 0 }); - m.insert("diamond_block", LegacyBlockState { id: 57, data: 0 }); - m.insert("crafting_table", LegacyBlockState { id: 58, data: 0 }); - m.insert("farmland", LegacyBlockState { id: 60, data: 0 }); - m.insert("furnace", LegacyBlockState { id: 61, data: 0 }); - m.insert("ladder", LegacyBlockState { id: 65, data: 0 }); - m.insert("rail", LegacyBlockState { id: 66, data: 0 }); - m.insert("lever", LegacyBlockState { id: 69, data: 0 }); - m.insert("stone_pressure_plate", LegacyBlockState { id: 70, data: 0 }); - m.insert("oak_pressure_plate", LegacyBlockState { id: 72, data: 0 }); - m.insert("redstone_ore", LegacyBlockState { id: 73, data: 0 }); - m.insert("redstone_torch", LegacyBlockState { id: 76, data: 0 }); - m.insert("stone_button", LegacyBlockState { id: 77, data: 0 }); - m.insert("snow", LegacyBlockState { id: 78, data: 0 }); - m.insert("ice", LegacyBlockState { id: 79, data: 0 }); - m.insert("snow_block", LegacyBlockState { id: 80, data: 0 }); - m.insert("cactus", LegacyBlockState { id: 81, data: 0 }); - m.insert("clay", LegacyBlockState { id: 82, data: 0 }); - m.insert("jukebox", LegacyBlockState { id: 84, data: 0 }); - m.insert("oak_fence", LegacyBlockState { id: 85, data: 0 }); - m.insert("netherrack", LegacyBlockState { id: 87, data: 0 }); - m.insert("soul_sand", LegacyBlockState { id: 88, data: 0 }); - m.insert("glowstone", LegacyBlockState { id: 89, data: 0 }); - m.insert("jack_o_lantern", LegacyBlockState { id: 91, data: 0 }); - m.insert("stone_bricks", LegacyBlockState { id: 98, data: 0 }); - m.insert("brown_mushroom_block", LegacyBlockState { id: 99, data: 0 }); - m.insert("red_mushroom_block", LegacyBlockState { id: 100, data: 0 }); - m.insert("iron_bars", LegacyBlockState { id: 101, data: 0 }); - m.insert("glass_pane", LegacyBlockState { id: 102, data: 0 }); - m.insert("melon", LegacyBlockState { id: 103, data: 0 }); - m.insert("vine", LegacyBlockState { id: 106, data: 0 }); - m.insert("oak_fence_gate", LegacyBlockState { id: 107, data: 0 }); - m.insert("brick_stairs", LegacyBlockState { id: 108, data: 0 }); - m.insert("stone_brick_stairs", LegacyBlockState { id: 109, data: 0 }); - m.insert("mycelium", LegacyBlockState { id: 110, data: 0 }); - m.insert("lily_pad", LegacyBlockState { id: 111, data: 0 }); - m.insert("nether_bricks", LegacyBlockState { id: 112, data: 0 }); - m.insert("nether_brick_fence", LegacyBlockState { id: 113, data: 0 }); - m.insert("nether_brick_stairs", LegacyBlockState { id: 114, data: 0 }); - m.insert("enchanting_table", LegacyBlockState { id: 116, data: 0 }); - m.insert("end_stone", LegacyBlockState { id: 121, data: 0 }); - m.insert("sandstone_stairs", LegacyBlockState { id: 128, data: 0 }); - m.insert("emerald_ore", LegacyBlockState { id: 129, data: 0 }); - m.insert("ender_chest", LegacyBlockState { id: 130, data: 0 }); - m.insert("tripwire_hook", LegacyBlockState { id: 131, data: 0 }); - m.insert("emerald_block", LegacyBlockState { id: 133, data: 0 }); - m.insert("spruce_stairs", LegacyBlockState { id: 134, data: 0 }); - m.insert("birch_stairs", LegacyBlockState { id: 135, data: 0 }); - m.insert("jungle_stairs", LegacyBlockState { id: 136, data: 0 }); - m.insert("command_block", LegacyBlockState { id: 1, data: 0 }); - m.insert("beacon", LegacyBlockState { id: 138, data: 0 }); - m.insert("cobblestone_wall", LegacyBlockState { id: 139, data: 0 }); - m.insert("flower_pot", LegacyBlockState { id: 140, data: 0 }); - m.insert("carrots", LegacyBlockState { id: 141, data: 0 }); - m.insert("potatoes", LegacyBlockState { id: 142, data: 0 }); - m.insert("oak_button", LegacyBlockState { id: 143, data: 0 }); - m.insert("anvil", LegacyBlockState { id: 145, data: 0 }); - m.insert("trapped_chest", LegacyBlockState { id: 146, data: 0 }); - m.insert("light_weighted_pressure_plate", LegacyBlockState { id: 147, data: 0 }); - m.insert("heavy_weighted_pressure_plate", LegacyBlockState { id: 148, data: 0 }); - m.insert("daylight_detector", LegacyBlockState { id: 151, data: 0 }); - m.insert("redstone_block", LegacyBlockState { id: 152, data: 0 }); - m.insert("quartz_ore", LegacyBlockState { id: 153, data: 0 }); - m.insert("hopper", LegacyBlockState { id: 154, data: 0 }); - m.insert("quartz_block", LegacyBlockState { id: 155, data: 0 }); - m.insert("quartz_stairs", LegacyBlockState { id: 156, data: 0 }); - m.insert("activator_rail", LegacyBlockState { id: 157, data: 0 }); - m.insert("dropper", LegacyBlockState { id: 158, data: 0 }); - m.insert("stained_hardened_clay", LegacyBlockState { id: 159, data: 0 }); - m.insert("stained_glass", LegacyBlockState { id: 95, data: 0 }); - m.insert("stained_glass_pane", LegacyBlockState { id: 160, data: 0 }); - m.insert("leaves2", LegacyBlockState { id: 161, data: 0 }); - m.insert("log2", LegacyBlockState { id: 162, data: 0 }); - m.insert("acacia_stairs", LegacyBlockState { id: 163, data: 0 }); - m.insert("dark_oak_stairs", LegacyBlockState { id: 164, data: 0 }); - m.insert("fern", LegacyBlockState { id: 31, data: 2 }); - m.insert("sugar_cane", LegacyBlockState { id: 83, data: 0 }); - m.insert("pumpkin", LegacyBlockState { id: 86, data: 0 }); - m.insert("carved_pumpkin", LegacyBlockState { id: 86, data: 0 }); - m.insert("nether_quartz_ore", LegacyBlockState { id: 153, data: 0 }); - m.insert("dragon_egg", LegacyBlockState { id: 122, data: 0 }); - m.insert("spawner", LegacyBlockState { id: 52, data: 0 }); - m.insert("tripwire", LegacyBlockState { id: 132, data: 0 }); - m.insert("sponge", LegacyBlockState { id: 19, data: 0 }); - m.insert("wet_sponge", LegacyBlockState { id: 19, data: 0 }); - m.insert("cauldron", LegacyBlockState { id: 118, data: 0 }); - m.insert("water_cauldron", LegacyBlockState { id: 118, data: 3 }); - m.insert("coal_block", LegacyBlockState { id: 173, data: 0 }); - m.insert("mushroom_stem", LegacyBlockState { id: 99, data: 10 }); - m.insert("smooth_stone", LegacyBlockState { id: 1, data: 0 }); - m.insert("infested_stone", LegacyBlockState { id: 1, data: 0 }); - m.insert("infested_stone_bricks", LegacyBlockState { id: 98, data: 0 }); - m.insert("infested_deepslate", LegacyBlockState { id: 1, data: 0 }); - m.insert( - "polished_blackstone_bricks", - LegacyBlockState { id: 98, data: 0 }, - ); - m.insert( - "cracked_polished_blackstone_bricks", - LegacyBlockState { id: 98, data: 2 }, - ); - m.insert("blackstone", LegacyBlockState { id: 4, data: 0 }); - m.insert("quartz_bricks", LegacyBlockState { id: 155, data: 0 }); - m.insert( - "chiseled_quartz_block", - LegacyBlockState { id: 155, data: 1 }, - ); - m.insert( - "chiseled_nether_bricks", - LegacyBlockState { id: 112, data: 0 }, - ); - m.insert("smooth_basalt", LegacyBlockState { id: 1, data: 0 }); - m.insert("pointed_dripstone", LegacyBlockState { id: 1, data: 0 }); - m.insert("lodestone", LegacyBlockState { id: 1, data: 0 }); - m.insert("structure_block", LegacyBlockState { id: 1, data: 0 }); - m.insert("stonecutter", LegacyBlockState { id: 4, data: 0 }); - m.insert("rooted_dirt", LegacyBlockState { id: 3, data: 0 }); - m.insert("moss_block", LegacyBlockState { id: 48, data: 0 }); - m.insert( - "dried_kelp_block", - LegacyBlockState { id: 170, data: 0 }, - ); - m.insert("crimson_stem", LegacyBlockState { id: 17, data: 0 }); - m.insert("warped_stem", LegacyBlockState { id: 17, data: 0 }); - m.insert( - "stripped_crimson_stem", - LegacyBlockState { id: 17, data: 0 }, - ); - m.insert( - "stripped_warped_stem", - LegacyBlockState { id: 17, data: 0 }, - ); - m.insert("azalea", LegacyBlockState { id: 18, data: 0 }); - m.insert("flowering_azalea", LegacyBlockState { id: 18, data: 0 }); - m.insert( - "big_dripleaf", - LegacyBlockState { id: 111, data: 0 }, - ); - m.insert( - "big_dripleaf_stem", - LegacyBlockState { id: 17, data: 0 }, - ); - m.insert("small_dripleaf", LegacyBlockState { id: 0, data: 0 }); - m.insert("hanging_roots", LegacyBlockState { id: 0, data: 0 }); - m.insert("spore_blossom", LegacyBlockState { id: 38, data: 0 }); - m.insert( - "twisting_vines", - LegacyBlockState { id: 106, data: 0 }, - ); - m.insert( - "twisting_vines_plant", - LegacyBlockState { id: 106, data: 0 }, - ); - m.insert("cave_vines", LegacyBlockState { id: 0, data: 0 }); - m.insert( - "cave_vines_plant", - LegacyBlockState { id: 0, data: 0 }, - ); - m.insert("glow_lichen", LegacyBlockState { id: 0, data: 0 }); - m.insert("cornflower", LegacyBlockState { id: 38, data: 0 }); - m.insert( - "lily_of_the_valley", - LegacyBlockState { id: 38, data: 0 }, - ); - m.insert("oxeye_daisy", LegacyBlockState { id: 38, data: 0 }); - m.insert("pink_tulip", LegacyBlockState { id: 38, data: 0 }); - m.insert("brain_coral", LegacyBlockState { id: 38, data: 0 }); - m.insert("bubble_coral", LegacyBlockState { id: 38, data: 0 }); - m.insert("fire_coral", LegacyBlockState { id: 38, data: 0 }); - m.insert("horn_coral", LegacyBlockState { id: 38, data: 0 }); - m.insert("tube_coral", LegacyBlockState { id: 38, data: 0 }); - m.insert( - "horn_coral_fan", - LegacyBlockState { id: 38, data: 0 }, - ); - m.insert( - "tube_coral_fan", - LegacyBlockState { id: 38, data: 0 }, - ); - m.insert("smoker", LegacyBlockState { id: 61, data: 0 }); - m.insert( - "grindstone", - LegacyBlockState { id: 145, data: 0 }, - ); - m.insert("bell", LegacyBlockState { id: 145, data: 0 }); - m.insert("loom", LegacyBlockState { id: 58, data: 0 }); - m.insert( - "smithing_table", - LegacyBlockState { id: 58, data: 0 }, - ); - m.insert( - "target", - LegacyBlockState { id: 70, data: 0 }, - ); - m.insert("chain", LegacyBlockState { id: 101, data: 0 }); - m.insert( - "lightning_rod", - LegacyBlockState { id: 101, data: 0 }, - ); - m.insert("lantern", LegacyBlockState { id: 50, data: 0 }); - m.insert( - "shroomlight", - LegacyBlockState { id: 89, data: 0 }, - ); - m.insert( - "soul_campfire", - LegacyBlockState { id: 51, data: 0 }, - ); - m.insert( - "bee_nest", - LegacyBlockState { id: 54, data: 0 }, - ); - m.insert( - "wither_skeleton_skull", - LegacyBlockState { id: 144, data: 0 }, - ); - m.insert( - "dragon_wall_head", - LegacyBlockState { id: 144, data: 0 }, - ); - m.insert( - "nether_portal", - LegacyBlockState { id: 90, data: 0 }, - ); - m.insert( - "white_candle", - LegacyBlockState { id: 50, data: 0 }, - ); - m.insert( - "orange_candle", - LegacyBlockState { id: 50, data: 0 }, - ); - m.insert( - "gray_candle", - LegacyBlockState { id: 50, data: 0 }, - ); - m.insert( - "cyan_candle", - LegacyBlockState { id: 50, data: 0 }, - ); - m.insert( - "lime_candle", - LegacyBlockState { id: 50, data: 0 }, - ); - m.insert( - "potted_blue_orchid", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_brown_mushroom", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_cactus", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_dandelion", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_oxeye_daisy", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_poppy", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "potted_red_mushroom", - LegacyBlockState { id: 140, data: 0 }, - ); - m.insert( - "powder_snow", - LegacyBlockState { id: 80, data: 0 }, - ); - m.insert( - "copper_ore", - LegacyBlockState { id: 15, data: 0 }, - ); - m.insert( - "oxidized_copper", - LegacyBlockState { id: 15, data: 0 }, - ); - m.insert( - "weathered_copper", - LegacyBlockState { id: 15, data: 0 }, - ); - m.insert( - "raw_copper_block", - LegacyBlockState { id: 42, data: 0 }, - ); - m.insert( - "raw_iron_block", - LegacyBlockState { id: 42, data: 0 }, - ); - m.insert( - "small_amethyst_bud", - LegacyBlockState { id: 20, data: 0 }, - ); - m.insert( - "medium_amethyst_bud", - LegacyBlockState { id: 20, data: 0 }, - ); - m.insert( - "large_amethyst_bud", - LegacyBlockState { id: 20, data: 0 }, - ); - m.insert( - "slime_block", - LegacyBlockState { id: 0, data: 0 }, - ); - m.insert("light", LegacyBlockState { id: 0, data: 0 }); - m.insert( - "scaffolding", - LegacyBlockState { id: 0, data: 0 }, - ); - m.insert( - "powder_snow_cauldron", - LegacyBlockState { id: 118, data: 0 }, - ); - m.insert( - "lava_cauldron", - LegacyBlockState { id: 118, data: 0 }, - ); - //neo: m.insert("help", neo {thisis: verytiring}); - m - }); - -static BLOCK_REMAP_TABLE: once_cell::sync::Lazy> = - once_cell::sync::Lazy::new(|| { - let mut m = HashMap::new(); - m.insert(174, 79); - m.insert(175, 0); - m.insert(165, 0); - m.insert(166, 0); - m.insert(167, 96); - m.insert(168, 1); - m.insert(169, 89); - m.insert(176, 0); - m.insert(177, 0); - m.insert(178, 151); - m.insert(179, 24); - m.insert(180, 128); - m.insert(181, 43); - m.insert(182, 44); - m.insert(183, 107); - m.insert(184, 107); - m.insert(185, 107); - m.insert(186, 107); - m.insert(187, 107); - m.insert(188, 85); - m.insert(189, 85); - m.insert(190, 85); - m.insert(191, 85); - m.insert(192, 85); - m.insert(193, 64); - m.insert(194, 64); - m.insert(195, 64); - m.insert(196, 64); - m.insert(197, 64); - m.insert(198, 0); - m.insert(199, 0); - m.insert(200, 0); - m.insert(201, 155); - m.insert(202, 155); - m.insert(203, 156); - m.insert(204, 43); - m.insert(205, 44); - m.insert(206, 121); - m.insert(207, 0); - m.insert(208, 2); - m.insert(209, 0); - m.insert(210, 1); - m.insert(211, 1); - m.insert(212, 79); - m.insert(213, 87); - m.insert(214, 112); - m.insert(215, 112); - m.insert(216, 1); - m.insert(217, 0); - m.insert(218, 0); - for i in 219..=234 { - m.insert(i, 0); - } - for i in 235..=250 { - m.insert(i, 159); - } - m.insert(251, 172); - m.insert(252, 12); - m - }); diff --git a/src-tauri/src/commands/java2lce/chunk.rs b/src-tauri/src/commands/java2lce/chunk.rs deleted file mode 100644 index 7947f51..0000000 --- a/src-tauri/src/commands/java2lce/chunk.rs +++ /dev/null @@ -1,1704 +0,0 @@ -use std::collections::HashMap; -use super::block_mapping::{self}; -use super::nbt; -use super::payload; -const CHUNK_BLOCKS: usize = 32768; -const CHUNK_NIBBLES: usize = 16384; -const HEIGHTMAP_SIZE: usize = 256; -const BIOMES_SIZE: usize = 256; -const STAIR_UPSIDE_DOWN_BIT: u8 = 4; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum JavaChunkFormat { - Unknown, - LegacyBlockArray, - LegacyAnvil, - ModernPalette, - ModernExtendedHeight, -} - -#[derive(Debug, Clone, Copy)] -pub struct JavaChunkFormatInfo { - pub format: JavaChunkFormat, - pub _has_level_wrapper: bool, - pub _data_version: i32, - pub _min_section_y: Option, - pub _max_section_y: Option, - pub has_modern_entity_tags: bool, -} - -impl JavaChunkFormatInfo { - pub fn is_section_based(&self) -> bool { - matches!( - self.format, - JavaChunkFormat::LegacyAnvil - | JavaChunkFormat::ModernPalette - | JavaChunkFormat::ModernExtendedHeight - ) - } - - pub fn uses_palette_sections(&self) -> bool { - matches!( - self.format, - JavaChunkFormat::ModernPalette | JavaChunkFormat::ModernExtendedHeight - ) - } - - pub fn uses_modern_content_schema(&self) -> bool { - self.uses_palette_sections() || self.has_modern_entity_tags - } - - pub fn requires_section_shift(&self) -> bool { - self.format == JavaChunkFormat::ModernExtendedHeight - } -} - -pub fn inspect_chunk(root_tag: &nbt::NbtCompound) -> JavaChunkFormatInfo { - let has_level_wrapper = root_tag.get("Level").is_some(); - let source_level = root_tag - .compound("Level") - .unwrap_or(root_tag); - - let data_version = root_tag - .int("DataVersion") - .or_else(|| { - root_tag - .compound("Level") - .and_then(|l| l.int("DataVersion")) - }) - .unwrap_or(0); - - let has_modern_entity_tags = source_level.contains("block_entities") || source_level.contains("entities"); - let has_legacy_block_arrays = source_level.contains("Blocks"); - let sections = source_level - .list("Sections") - .or_else(|| source_level.list("sections")); - - let mut has_sections = false; - let mut has_palette_sections = false; - let mut min_section_y: Option = None; - let mut max_section_y: Option = None; - if let Some(sects) = sections { - has_sections = !sects.is_empty(); - for tag in sects { - if let nbt::NbtValue::Compound(section) = tag { - if let Some(sy) = read_section_y(section) { - min_section_y = Some(min_section_y.map_or(sy, |v| v.min(sy))); - max_section_y = Some(max_section_y.map_or(sy, |v| v.max(sy))); - } - if section_uses_palette_storage(section) { - has_palette_sections = true; - } - } - } - } - - let format = if has_palette_sections { - let has_extended = min_section_y.map_or(false, |v| v < 0) - || max_section_y.map_or(false, |v| v > 15); - if has_extended { - JavaChunkFormat::ModernExtendedHeight - } else { - JavaChunkFormat::ModernPalette - } - } else if has_sections { - JavaChunkFormat::LegacyAnvil - } else if has_legacy_block_arrays { - JavaChunkFormat::LegacyBlockArray - } else { - JavaChunkFormat::Unknown - }; - - JavaChunkFormatInfo { - format, - _has_level_wrapper: has_level_wrapper, - _data_version: data_version, - _min_section_y: min_section_y, - _max_section_y: max_section_y, - has_modern_entity_tags, - } -} - -pub fn read_section_y(section: &nbt::NbtCompound) -> Option { - if let Some(b) = section.byte("Y") { - return Some(b as i8 as i32); - } - if let Some(i) = section.int("Y") { - return Some(i); - } - if let Some(s) = section.short("Y") { - return Some(s as i32); - } - None -} - -fn section_uses_palette_storage(section: &nbt::NbtCompound) -> bool { - section.contains("block_states") - || section.contains("Palette") - || section.contains("BlockStates") -} - -fn get_byte_array_or_default(compound: &nbt::NbtCompound, name: &str, default_size: usize) -> Vec { - if let Some(bytes) = compound.byte_array(name) { - let mut v = bytes.to_vec(); - if v.len() < default_size { - v.resize(default_size, 0); - } else { - v.truncate(default_size); - } - return v; - } - - if let Some(ints) = compound.int_array(name) { - let mut v = vec![0u8; default_size]; - let len = ints.len().min(default_size); - for (i, &val) in ints.iter().take(len).enumerate() { - v[i] = val.clamp(0, 255) as u8; - } - return v; - } - - vec![0u8; default_size] -} - -struct DecodedSection { - section_y: i32, - blocks: Vec, - data: Vec, - sky_light: Option>, - block_light: Option>, - non_air_count: u32, -} - -fn count_non_air(blocks: &[u8]) -> u32 { - blocks.iter().filter(|&&b| b != 0).count() as u32 -} - -fn try_decode_section_blocks( - section: &nbt::NbtCompound, -) -> Option<(Vec, Vec)> { - if let Some(old_blocks) = section.byte_array("Blocks") { - if old_blocks.len() >= 4096 { - let blocks = old_blocks[..4096].to_vec(); - let data = section - .byte_array("Data") - .map(|d| d.to_vec()) - .unwrap_or_else(|| vec![0u8; CHUNK_NIBBLES]); - return Some((blocks, data)); - } - } - try_decode_palette_section(section) -} - -fn try_decode_palette_section(section: &nbt::NbtCompound) -> Option<(Vec, Vec)> { - let mut blocks = vec![0u8; 4096]; - let mut data = vec![0u8; 2048]; - let block_states_container = section.compound("block_states"); - let palette = section - .list("Palette") - .or_else(|| { - block_states_container - .and_then(|bs| bs.list("palette")) - }); - - let palette = palette?; - if palette.is_empty() { - return None; - } - - if palette.len() == 1 { - if let nbt::NbtValue::Compound(entry) = &palette[0] { - let lb = block_mapping::map_modern_block_state(entry); - blocks.fill(lb.id); - if lb.data != 0 { - for i in 0..4096 { - nbt::set_nibble(&mut data, i, lb.data); - } - } - return Some((blocks, data)); - } - return None; - } - - let block_states_tag = section - .long_array("BlockStates") - .or_else(|| { - block_states_container - .and_then(|bs| bs.long_array("data")) - })?; - - if block_states_tag.is_empty() { - return None; - } - - let bits_per_block = get_bits_required(palette.len() - 1).max(4); - let values_per_long = (64 / bits_per_block).max(1); - let expected_long_count = (4096 + values_per_long - 1) / values_per_long; - let use_padded = block_states_tag.len() == expected_long_count; - for i in 0..4096 { - let palette_index = if use_padded { - read_padded_block_state(block_states_tag, bits_per_block, i) - } else { - read_compact_block_state(block_states_tag, bits_per_block, i) - }; - - if (palette_index as usize) >= palette.len() { - continue; - } - - if let nbt::NbtValue::Compound(entry) = &palette[palette_index] { - let legacy = block_mapping::map_modern_block_state(entry); - blocks[i] = legacy.id; - if legacy.data != 0 { - nbt::set_nibble(&mut data, i, legacy.data); - } - } - } - - Some((blocks, data)) -} - -fn get_bits_required(value: usize) -> usize { - let mut bits = 0; - let mut v = value; - while v > 0 { - bits += 1; - v >>= 1; - } - bits.max(1) -} - -fn read_padded_block_state(block_states: &[i64], bits_per_block: usize, index: usize) -> usize { - let values_per_long = (64 / bits_per_block).max(1); - let long_index = index / values_per_long; - let bit_offset = (index % values_per_long) * bits_per_block; - let mask = (1u64 << bits_per_block) - 1; - ((block_states[long_index] as u64 >> bit_offset) & mask) as usize -} - -fn read_compact_block_state(block_states: &[i64], bits_per_block: usize, index: usize) -> usize { - let start_bit = index * bits_per_block; - let long_index = start_bit >> 6; - let bit_offset = start_bit & 63; - let mask = (1u64 << bits_per_block) - 1; - let mut value = block_states[long_index] as u64 >> bit_offset; - let bits_read = 64 - bit_offset; - if bits_read < bits_per_block && long_index + 1 < block_states.len() { - value |= (block_states[long_index + 1] as u64) << bits_read; - } - (value & mask) as usize -} - -fn flatten_anvil_sections( - level: &nbt::NbtCompound, - format_info: &JavaChunkFormatInfo, - global_section_shift: &mut Option, -) -> (Vec, Vec, Vec, Vec) { - let mut blocks = vec![0u8; CHUNK_BLOCKS]; - let mut data = vec![0u8; CHUNK_NIBBLES]; - let mut sky_light = vec![0xFFu8; CHUNK_NIBBLES]; - let mut block_light = vec![0u8; CHUNK_NIBBLES]; - let sections = level - .list("Sections") - .or_else(|| level.list("sections")); - - let sections = match sections { - Some(s) => s, - None => return (blocks, data, sky_light, block_light), - }; - - let mut decoded_sections: Vec = Vec::new(); - for tag in sections { - if let nbt::NbtValue::Compound(section) = tag { - let section_y = match read_section_y(section) { - Some(y) => y, - None => continue, - }; - - let (s_blocks, s_data) = match try_decode_section_blocks(section) { - Some(v) => v, - None => continue, - }; - - let s_sky = section - .byte_array("SkyLight") - .or_else(|| section.byte_array("sky_light")) - .map(|b| b.to_vec()); - let s_block = section - .byte_array("BlockLight") - .or_else(|| section.byte_array("block_light")) - .map(|b| b.to_vec()); - - let non_air = count_non_air(&s_blocks); - decoded_sections.push(DecodedSection { - section_y, - blocks: s_blocks, - data: s_data, - sky_light: s_sky, - block_light: s_block, - non_air_count: non_air, - }); - } - } - - if decoded_sections.is_empty() { - return (blocks, data, sky_light, block_light); - } - - let mut section_shift = 0; - if format_info.requires_section_shift() { - if global_section_shift.is_none() { - let anchor = decoded_sections - .iter() - .max_by_key(|s| (s.non_air_count, -(s.section_y - 4).abs())) - .map(|s| s.section_y) - .unwrap_or(4); - *global_section_shift = Some(anchor - 4); - } - section_shift = global_section_shift.unwrap_or(0); - } - - for section in &decoded_sections { - let remapped_y = section.section_y - section_shift; - if remapped_y < 0 || remapped_y > 7 { - continue; - } - - let base_y = remapped_y * 16; - for i in 0..4096 { - let x = i & 0x0F; - let z = (i >> 4) & 0x0F; - let y = (i >> 8) & 0x0F; - let global_y = base_y + y as i32; - if global_y < 0 || global_y >= 128 { - continue; - } - let flat_index = ((x * 16) + z) * 128 + global_y as usize; - if flat_index < CHUNK_BLOCKS { - blocks[flat_index] = section.blocks[i]; - if section.data.len() > i { - nbt::set_nibble(&mut data, flat_index, nbt::get_nibble(§ion.data, i)); - } - if let Some(ref sky) = section.sky_light { - if sky.len() > i { - nbt::set_nibble(&mut sky_light, flat_index, nbt::get_nibble(sky, i)); - } - } - if let Some(ref bl) = section.block_light { - if bl.len() > i { - nbt::set_nibble(&mut block_light, flat_index, nbt::get_nibble(bl, i)); - } - } - } - } - } - - (blocks, data, sky_light, block_light) -} - -pub fn convert_chunk( - root_tag: &nbt::NbtCompound, - new_chunk_x: i32, - new_chunk_z: i32, - preserve_dynamic: bool, - global_section_shift: &mut Option, -) -> Vec { - let level = - build_legacy_chunk_level(root_tag, new_chunk_x, new_chunk_z, preserve_dynamic, global_section_shift); - payload::encode_legacy_nbt(&level) -} -/* -//neo: unused -pub fn convert_chunk_for_save( - root_tag: &nbt::NbtCompound, - new_chunk_x: i32, - new_chunk_z: i32, - preserve_dynamic: bool, - global_section_shift: &mut Option, -) -> Vec { - let level = build_legacy_chunk_level(root_tag, new_chunk_x, new_chunk_z, preserve_dynamic, global_section_shift); - payload::encode_compressed_storage(&level) -}*/ - -fn build_legacy_chunk_level( - root_tag: &nbt::NbtCompound, - new_chunk_x: i32, - new_chunk_z: i32, - preserve_dynamic: bool, - global_section_shift: &mut Option, -) -> nbt::NbtCompound { - let format_info = inspect_chunk(root_tag); - let source_level = root_tag - .compound("Level") - .unwrap_or(root_tag); - let is_modern = format_info.uses_modern_content_schema(); - let (mut blocks, mut data, mut sky_light, block_light) = - if format_info.is_section_based() { - flatten_anvil_sections(source_level, &format_info, global_section_shift) - } else { - let b = get_byte_array_or_default(source_level, "Blocks", CHUNK_BLOCKS); - let d = get_byte_array_or_default(source_level, "Data", CHUNK_NIBBLES); - let s = get_byte_array_or_default(source_level, "SkyLight", CHUNK_NIBBLES); - let bl = get_byte_array_or_default(source_level, "BlockLight", CHUNK_NIBBLES); - (b, d, s, bl) - }; - - let height_map = get_byte_array_or_default(source_level, "HeightMap", HEIGHTMAP_SIZE); - let mut biomes = get_byte_array_or_default(source_level, "Biomes", BIOMES_SIZE); - if is_modern { - biomes.fill(1); - } - - block_mapping::remap_blocks(&mut blocks, &mut data); - let last_update = source_level.long("LastUpdate").unwrap_or(0); - let inhabited_time = source_level.long("InhabitedTime").unwrap_or(0); - const TERRAIN_POPULATED_FLAGS: i16 = 0; - if sky_light.iter().all(|&b| b == 0) { - sky_light.fill(0xFF); - } - let mut level = nbt::NbtCompound::new("Level"); - level.insert("xPos", nbt::NbtValue::Int(new_chunk_x)); - level.insert("zPos", nbt::NbtValue::Int(new_chunk_z)); - level.insert("LastUpdate", nbt::NbtValue::Long(last_update)); - level.insert("InhabitedTime", nbt::NbtValue::Long(inhabited_time)); - level.insert("Blocks", nbt::NbtValue::ByteArray(blocks)); - level.insert("Data", nbt::NbtValue::ByteArray(data)); - level.insert("SkyLight", nbt::NbtValue::ByteArray(sky_light)); - level.insert("BlockLight", nbt::NbtValue::ByteArray(block_light)); - level.insert("HeightMap", nbt::NbtValue::ByteArray(height_map)); - level.insert("TerrainPopulatedFlags", nbt::NbtValue::Short(TERRAIN_POPULATED_FLAGS)); - level.insert("Biomes", nbt::NbtValue::ByteArray(biomes)); - let source_chunk_x = source_level.int("xPos").unwrap_or(new_chunk_x); - let source_chunk_z = source_level.int("zPos").unwrap_or(new_chunk_z); - let block_offset_x = (source_chunk_x - new_chunk_x) * 16; - let block_offset_z = (source_chunk_z - new_chunk_z) * 16; - if preserve_dynamic && !is_modern { - let mut entities: Vec = source_level - .list("Entities") - .map(|l| l.to_vec()) - .unwrap_or_default(); - remap_entity_positions(&mut entities, block_offset_x, block_offset_z); - level.insert("Entities", nbt::NbtValue::List(entities)); - } else { - level.insert("Entities", nbt::NbtValue::List(Vec::new())); - } - - let mut tile_entities = if preserve_dynamic && !is_modern { - build_compatible_tile_entities(source_level, false) - } else { - build_safe_sign_tile_entities(source_level, is_modern) - }; - remove_unsupported_tile_entities(&mut tile_entities); - remap_tile_entity_positions(&mut tile_entities, block_offset_x, block_offset_z); - level.insert("TileEntities", nbt::NbtValue::List(tile_entities)); - if preserve_dynamic && !is_modern { - if let Some(ticks) = source_level.list("TileTicks") { - let remapped = remap_tile_tick_positions(ticks, block_offset_x, block_offset_z); - level.insert("TileTicks", nbt::NbtValue::List(remapped)); - } else if let Some(ticks) = source_level.list("block_ticks") { - let remapped = remap_tile_tick_positions(ticks, block_offset_x, block_offset_z); - level.insert("TileTicks", nbt::NbtValue::List(remapped)); - } - } - - level -} - -fn build_compatible_tile_entities( - source_level: &nbt::NbtCompound, - is_modern: bool, -) -> Vec { - if !is_modern { - let tiles = source_level.list("TileEntities"); - if let Some(t) = tiles { - return t.to_vec(); - } - let tiles2 = source_level.list("block_entities"); - if let Some(t) = tiles2 { - return t.to_vec(); - } - return Vec::new(); - } - build_safe_sign_tile_entities(source_level, true) -} - -fn build_safe_sign_tile_entities( - source_level: &nbt::NbtCompound, - is_modern: bool, -) -> Vec { - let mut result = Vec::new(); - let source = if is_modern { - source_level - .list("block_entities") - .or_else(|| source_level.list("TileEntities")) - } else { - source_level - .list("TileEntities") - .or_else(|| source_level.list("block_entities")) - }; - - let source = match source { - Some(s) => s, - None => return result, - }; - - for tag in source { - if let nbt::NbtValue::Compound(block_entity) = tag { - let id = block_entity.string("id").unwrap_or(""); - let is_sign = if is_modern { - is_modern_sign_tile_entity(id) - } else { - id == "Sign" || id == "minecraft:sign" - }; - if !is_sign { - continue; - } - let sign = build_safe_legacy_sign_tile_entity(block_entity, is_modern); - result.push(nbt::NbtValue::Compound(sign)); - } - } - - result -} - -fn is_modern_sign_tile_entity(id: &str) -> bool { - let stripped = id.strip_prefix("minecraft:").unwrap_or(id); - matches!( - stripped, - "sign" - | "hanging_sign" - | "oak_sign" - | "spruce_sign" - | "birch_sign" - | "jungle_sign" - | "acacia_sign" - | "dark_oak_sign" - | "mangrove_sign" - | "cherry_sign" - | "bamboo_sign" - | "crimson_sign" - | "warped_sign" - | "oak_hanging_sign" - | "spruce_hanging_sign" - | "birch_hanging_sign" - | "jungle_hanging_sign" - | "acacia_hanging_sign" - | "dark_oak_hanging_sign" - | "mangrove_hanging_sign" - | "cherry_hanging_sign" - | "bamboo_hanging_sign" - | "crimson_hanging_sign" - | "warped_hanging_sign" - ) -} - -fn read_tile_entity_coord(compound: &nbt::NbtCompound, name: &str) -> i32 { - compound.int(name) - .map(|v| v as i32) - .or_else(|| compound.short(name).map(|v| v as i32)) - .or_else(|| compound.byte(name).map(|v| v as i32)) - .unwrap_or(0) -} - -fn extract_modern_sign_lines(block_entity: &nbt::NbtCompound) -> [String; 4] { - let mut lines: [String; 4] = Default::default(); - if let Some(front_text) = block_entity.compound("front_text") { - if let Some(messages) = front_text.list("messages") { - for i in 0..4.min(messages.len()) { - if let nbt::NbtValue::String(s) = &messages[i] { - lines[i] = sanitize_legacy_sign_line(&simplify_sign_text(s)); - } - } - return lines; - } - } - - for i in 0..4 { - let key = format!("Text{}", i + 1); - let value = block_entity.string(&key).unwrap_or(""); - lines[i] = sanitize_legacy_sign_line(&simplify_sign_text(value)); - } - - lines -} - -fn extract_legacy_sign_lines(block_entity: &nbt::NbtCompound) -> [String; 4] { - let mut lines: [String; 4] = Default::default(); - for i in 0..4 { - let key = format!("Text{}", i + 1); - let value = block_entity.string(&key).unwrap_or(""); - lines[i] = sanitize_legacy_sign_line(&simplify_sign_text(value)); - } - lines -} - -fn sanitize_legacy_sign_line(raw: &str) -> String { - let mut builder = String::new(); - for ch in raw.chars() { - if ch == '\r' || ch == '\n' || ch == '\t' || ch == '\0' { - continue; - } - if ch.is_control() { - continue; - } - builder.push(ch); - if builder.len() >= 15 { - break; - } - } - builder -} - -fn simplify_sign_text(raw: &str) -> String { - let raw = raw.trim(); - if !(raw.starts_with('{') || raw.starts_with('[') || raw.starts_with('"')) { - return raw.to_string(); - } - - if let Ok(doc) = serde_json::from_str::(raw) { - let mut builder = String::new(); - append_json_text(&doc, &mut builder); - return builder; - } - - raw.trim_matches('"').to_string() -} - -fn append_json_text(element: &serde_json::Value, builder: &mut String) { - match element { - serde_json::Value::String(s) => builder.push_str(s), - serde_json::Value::Array(arr) => { - for item in arr { - append_json_text(item, builder); - } - } - serde_json::Value::Object(obj) => { - if let Some(serde_json::Value::String(text)) = obj.get("text") { - builder.push_str(text); - } - if let Some(extra) = obj.get("extra") { - append_json_text(extra, builder); - } - } - _ => {} - } -} - -fn build_safe_legacy_sign_tile_entity( - block_entity: &nbt::NbtCompound, - is_modern: bool, -) -> nbt::NbtCompound { - let x = read_tile_entity_coord(block_entity, "x"); - let y = read_tile_entity_coord(block_entity, "y"); - let z = read_tile_entity_coord(block_entity, "z"); - let lines = if is_modern { - extract_modern_sign_lines(block_entity) - } else { - extract_legacy_sign_lines(block_entity) - }; - - let mut sign = nbt::NbtCompound::new(""); - sign.insert("id", nbt::NbtValue::String("Sign".to_string())); - sign.insert("x", nbt::NbtValue::Int(x)); - sign.insert("y", nbt::NbtValue::Int(y)); - sign.insert("z", nbt::NbtValue::Int(z)); - sign.insert("Text1", nbt::NbtValue::String(lines[0].clone())); - sign.insert("Text2", nbt::NbtValue::String(lines[1].clone())); - sign.insert("Text3", nbt::NbtValue::String(lines[2].clone())); - sign.insert("Text4", nbt::NbtValue::String(lines[3].clone())); - sign -} - -fn remap_tile_tick_positions( - ticks: &[nbt::NbtValue], - block_offset_x: i32, - block_offset_z: i32, -) -> Vec { - if block_offset_x == 0 && block_offset_z == 0 { - return ticks.to_vec(); - } - let mut result = Vec::new(); - for tag in ticks { - if let nbt::NbtValue::Compound(mut tick) = tag.clone() { - if let Some(nbt::NbtValue::Int(x)) = tick.get_mut("x") { - *x -= block_offset_x; - } - if let Some(nbt::NbtValue::Int(z)) = tick.get_mut("z") { - *z -= block_offset_z; - } - result.push(nbt::NbtValue::Compound(tick)); - } - } - result -} - -fn remap_entity_positions(entities: &mut Vec, block_offset_x: i32, block_offset_z: i32) { - if block_offset_x == 0 && block_offset_z == 0 { - return; - } - for tag in entities.iter_mut() { - if let nbt::NbtValue::Compound(entity) = tag { - if let Some(nbt::NbtValue::List(pos)) = entity.get_mut("Pos") { - if pos.len() >= 3 { - if let nbt::NbtValue::Double(x) = &mut pos[0] { - *x -= block_offset_x as f64; - } - if let nbt::NbtValue::Double(z) = &mut pos[2] { - *z -= block_offset_z as f64; - } - } - } - if let Some(nbt::NbtValue::Compound(riding)) = entity.get_mut("Riding") { - let mut inner = vec![nbt::NbtValue::Compound(riding.clone())]; - remap_entity_positions(&mut inner, block_offset_x, block_offset_z); - if let Some(nbt::NbtValue::Compound(updated)) = inner.into_iter().next() { - *riding = updated; - } - } - } - } -} - -fn remove_unsupported_tile_entities(tile_entities: &mut Vec) { - tile_entities.retain(|tag| { - if let nbt::NbtValue::Compound(te) = tag { - let id = te.string("id").unwrap_or(""); - return id != "Control" && id != "minecraft:command_block" && id != "CommandBlock"; - } - false - }); -} - -fn remap_tile_entity_positions(tile_entities: &mut Vec, block_offset_x: i32, block_offset_z: i32) { - if block_offset_x == 0 && block_offset_z == 0 { - return; - } - for tag in tile_entities.iter_mut() { - if let nbt::NbtValue::Compound(te) = tag { - if let Some(nbt::NbtValue::Int(x)) = te.get_mut("x") { - *x -= block_offset_x; - } - if let Some(nbt::NbtValue::Int(z)) = te.get_mut("z") { - *z -= block_offset_z; - } - } - } -} - -pub fn build_modern_anvil_level( - legacy_level: &nbt::NbtCompound, - chunk_x: i32, - chunk_z: i32, -) -> nbt::NbtCompound { - let default_blocks = vec![0u8; 32768]; - let default_data = vec![0u8; 16384]; - let old_blocks_ref = legacy_level - .byte_array("Blocks") - .unwrap_or(&default_blocks); - let old_data_ref = legacy_level - .byte_array("Data") - .unwrap_or(&default_data); - - let mut section_tags: Vec = Vec::new(); - for section_y in 0..8 { - let mut palette_list: Vec = Vec::new(); - let mut palette_dict: HashMap = HashMap::new(); - let mut indices = [0i32; 4096]; - let mut has_non_air = false; - for y in 0..16 { - for z in 0..16 { - for x in 0..16 { - let global_y = section_y * 16 + y; - let legacy_flat_index = ((x * 16) + z) * 128 + global_y; - if legacy_flat_index >= old_blocks_ref.len() { - continue; - } - let block_id = old_blocks_ref[legacy_flat_index]; - let meta = nbt::get_nibble(old_data_ref, legacy_flat_index); - let modern_state = get_contextual_block_state(block_id, meta, x, global_y, z, old_blocks_ref, old_data_ref); - if modern_state != "minecraft:air" { - has_non_air = true; - } - - let idx = *palette_dict - .entry(modern_state.clone()) - .or_insert_with(|| { - let idx = palette_list.len(); - palette_list.push(modern_state); - idx - }); - - indices[y * 256 + z * 16 + x] = idx as i32; - } - } - } - - if !has_non_air && section_y > 0 { - continue; - } - - let mut section_tag = nbt::NbtCompound::new(""); - section_tag.insert("Y", nbt::NbtValue::Byte(section_y as i8)); - let mut block_states_tag = nbt::NbtCompound::new("block_states"); - let mut nbt_palette: Vec = Vec::new(); - for state in &palette_list { - let mut p_tag = nbt::NbtCompound::new(""); - if let Some(bracket_idx) = state.find('[') { - let name = &state[..bracket_idx]; - let props_str = &state[bracket_idx + 1..state.len() - 1]; - p_tag.insert("Name", nbt::NbtValue::String(name.to_string())); - let mut props_compound = nbt::NbtCompound::new("Properties"); - for prop in props_str.split(',') { - let kv: Vec<&str> = prop.splitn(2, '=').collect(); - if kv.len() == 2 { - props_compound - .insert(kv[0], nbt::NbtValue::String(kv[1].to_string())); - } - } - p_tag.insert("Properties", nbt::NbtValue::Compound(props_compound)); - } else { - p_tag.insert("Name", nbt::NbtValue::String(state.to_string())); - } - nbt_palette.push(nbt::NbtValue::Compound(p_tag)); - } - block_states_tag.insert("palette", nbt::NbtValue::List(nbt_palette)); - if palette_list.len() > 1 { - let bits_per_block = (64.0 / (palette_list.len() as f64).log2().ceil()).floor().max(4.0) as usize; - let values_per_long = 64 / bits_per_block; - let long_count = ((4096.0 / values_per_long as f64).ceil()) as usize; - let mut data_array = vec![0i64; long_count]; - let mut current_long: u64 = 0; - let mut blocks_in_current_long = 0; - let mut long_index = 0; - for i in 0..4096 { - let val = indices[i] as u64; - current_long |= val << (blocks_in_current_long * bits_per_block); - blocks_in_current_long += 1; - if blocks_in_current_long >= values_per_long { - data_array[long_index] = current_long as i64; - long_index += 1; - current_long = 0; - blocks_in_current_long = 0; - } - } - - if blocks_in_current_long > 0 { - data_array[long_index] = current_long as i64; - } - - block_states_tag.insert("data", nbt::NbtValue::LongArray(data_array)); - } - - section_tag.insert("block_states", nbt::NbtValue::Compound(block_states_tag)); - let mut biomes_tag = nbt::NbtCompound::new("biomes"); - let biome_palette = nbt::NbtValue::List(vec![nbt::NbtValue::String( - "minecraft:plains".to_string(), - )]); - biomes_tag.insert("palette", biome_palette); - section_tag.insert("biomes", nbt::NbtValue::Compound(biomes_tag)); - section_tags.push(nbt::NbtValue::Compound(section_tag)); - } - - let mut root = nbt::NbtCompound::new(""); - root.insert("xPos", nbt::NbtValue::Int(chunk_x)); - root.insert("zPos", nbt::NbtValue::Int(chunk_z)); - root.insert("yPos", nbt::NbtValue::Int(0)); - root.insert("Status", nbt::NbtValue::String("full".to_string())); - let mut block_entities: Vec = Vec::new(); - if let Some(old_te_list) = legacy_level.list("TileEntities") { - for old_te in old_te_list { - if let nbt::NbtValue::Compound(old_te_comp) = old_te { - let mut new_te = old_te_comp.clone(); - let id = new_te.string("id").unwrap_or("").to_string(); - let new_id = match id.as_str() { - "Chest" => Some("minecraft:chest"), - "Furnace" => Some("minecraft:furnace"), - "BrewingStand" => Some("minecraft:brewing_stand"), - "EnchantTable" => Some("minecraft:enchanting_table"), - "Trap" => Some("minecraft:dispenser"), - "MobSpawner" => Some("minecraft:mob_spawner"), - "Control" => Some("minecraft:command_block"), - "Beacon" => Some("minecraft:beacon"), - "Skull" => Some("minecraft:skull"), - "Sign" => Some("minecraft:sign"), - "Cauldron" => Some("minecraft:cauldron"), - "Dropper" => Some("minecraft:dropper"), - "Hopper" => Some("minecraft:hopper"), - "Comparator" => Some("minecraft:comparator"), - "RecordPlayer" => Some("minecraft:jukebox"), - "Banner" => Some("minecraft:banner"), - _ if id.starts_with("minecraft:") => Some(id.as_str()), - _ => None, - }; - - if let Some(nid) = new_id { - new_te.insert("id", nbt::NbtValue::String(nid.to_string())); - block_entities.push(nbt::NbtValue::Compound(new_te)); - } - } - } - } - - for i in 0..old_blocks_ref.len().min(32768) { - if old_blocks_ref[i] == 26 { - let y = i % 128; - let z = (i / 128) % 16; - let x = i / 2048; - let mut bed_te = nbt::NbtCompound::new(""); - bed_te.insert("id", nbt::NbtValue::String("minecraft:bed".to_string())); - bed_te.insert("color", nbt::NbtValue::Int(14)); - bed_te.insert("x", nbt::NbtValue::Int(chunk_x * 16 + x as i32)); - bed_te.insert("y", nbt::NbtValue::Int(y as i32)); - bed_te.insert("z", nbt::NbtValue::Int(chunk_z * 16 + z as i32)); - block_entities.push(nbt::NbtValue::Compound(bed_te)); - } - } - - root.insert( - "block_entities", - nbt::NbtValue::List(block_entities), - ); - root.insert("sections", nbt::NbtValue::List(section_tags)); - root -} - -fn get_contextual_block_state( - block_id: u8, - meta: u8, - x: usize, - global_y: usize, - z: usize, - old_blocks: &[u8], - old_data: &[u8], -) -> String { - let modern_state = get_modern_block_name(block_id, meta); - let get_neighbor = |nx: i32, ny: i32, nz: i32| -> (u8, u8) { - if nx < 0 || nx > 15 || ny < 0 || ny > 127 || nz < 0 || nz > 15 { - return (0, 0); - } - let idx = ((nx as usize * 16) + nz as usize) * 128 + ny as usize; - if idx >= old_blocks.len() { - return (0, 0); - } - let n_id = old_blocks[idx]; - let n_meta = nbt::get_nibble(old_data, idx); - (n_id, n_meta) - }; - - let bracket_index = modern_state.find('['); - let name = if let Some(bi) = bracket_index { - &modern_state[..bi] - } else { - &modern_state - }; - let mut properties: HashMap = HashMap::new(); - if let Some(bi) = bracket_index { - let props_str = &modern_state[bi + 1..modern_state.len() - 1]; - for prop in props_str.split(',') { - let kv: Vec<&str> = prop.splitn(2, '=').collect(); - if kv.len() == 2 { - properties.insert(kv[0].to_string(), kv[1].to_string()); - } - } - } - - let mut properties_changed = false; - if block_id == 64 || block_id == 71 || (block_id >= 193 && block_id <= 197) { - let is_top = (meta & 8) == 8; - properties.insert("half".to_string(), if is_top { "upper" } else { "lower" }.to_string()); - if is_top { - properties.insert( - "hinge".to_string(), - if (meta & 1) == 1 { "right" } else { "left" }.to_string(), - ); - let (bottom_id, bottom_meta) = get_neighbor(x as i32, global_y as i32 - 1, z as i32); - if bottom_id == block_id { - let facing_meta = bottom_meta & 3; - properties.insert( - "facing".to_string(), - match facing_meta { - 0 => "east", - 1 => "south", - 2 => "west", - _ => "north", - } - .to_string(), - ); - properties.insert( - "open".to_string(), - if (bottom_meta & 4) == 4 { "true" } else { "false" }.to_string(), - ); - } else { - properties.insert("facing".to_string(), "east".to_string()); - properties.insert("open".to_string(), "false".to_string()); - } - } else { - let facing_meta = meta & 3; - properties.insert( - "facing".to_string(), - match facing_meta { - 0 => "east", - 1 => "south", - 2 => "west", - _ => "north", - } - .to_string(), - ); - properties.insert( - "open".to_string(), - if (meta & 4) == 4 { "true" } else { "false" }.to_string(), - ); - let (top_id, top_meta) = get_neighbor(x as i32, global_y as i32 + 1, z as i32); - properties.insert( - "hinge".to_string(), - if top_id == block_id { - if (top_meta & 1) == 1 { "right" } else { "left" } - } else { - "left" - } - .to_string(), - ); - } - properties_changed = true; - } else if block_id == 63 || block_id == 68 { - if block_id == 68 { - properties.insert( - "facing".to_string(), - match meta { - 2 => "north", - 3 => "south", - 4 => "west", - _ => "east", - } - .to_string(), - ); - } else { - properties.insert("rotation".to_string(), meta.to_string()); - } - properties.remove("waterlogged"); - properties_changed = true; - } else if block_id == 50 || block_id == 75 || block_id == 76 { - if meta >= 1 && meta <= 4 { - properties.insert( - "facing".to_string(), - match meta { - 1 => "east", - 2 => "west", - 3 => "south", - _ => "north", - } - .to_string(), - ); - } - if block_id == 76 { - properties.insert("lit".to_string(), "true".to_string()); - } else if block_id == 75 { - properties.insert("lit".to_string(), "false".to_string()); - } - properties_changed = true; - } else if block_id == 54 || block_id == 146 { - let facing = match meta { - 2 => "north", - 3 => "south", - 4 => "west", - 5 => "east", - _ => "south", - }; - properties.insert("type".to_string(), "single".to_string()); - properties.insert("facing".to_string(), facing.to_string()); - let dirs = [(-1i32, 0i32), (1, 0), (0, -1), (0, 1)]; - for (dx, dz) in dirs { - let (nid, _) = get_neighbor(x as i32 + dx, global_y as i32, z as i32 + dz); - if nid == block_id { - let is_left = match facing { - "north" => dx == -1, - "south" => dx == 1, - "west" => dz == 1, - "east" => dz == -1, - _ => false, - }; - properties.insert( - "type".to_string(), - if is_left { "right" } else { "left" }.to_string(), - ); - break; - } - } - properties_changed = true; - } else if is_stair_legacy(block_id) { - let facing = get_stair_facing(meta); - let half = if (meta & STAIR_UPSIDE_DOWN_BIT) != 0 { - "top" - } else { - "bottom" - }; - properties.insert("facing".to_string(), facing.to_string()); - properties.insert("half".to_string(), half.to_string()); - properties.insert("shape".to_string(), "straight".to_string()); - let (front_dx, front_dz) = match facing { - "north" => (0i32, 1i32), - "south" => (0, -1), - "west" => (1, 0), - "east" => (-1, 0), - _ => (0, 0), - }; - let (back_dx, back_dz) = match facing { - "north" => (0i32, -1i32), - "south" => (0, 1), - "west" => (-1, 0), - "east" => (1, 0), - _ => (0, 0), - }; - - let back_neighbor = get_neighbor(x as i32 + back_dx, global_y as i32, z as i32 + back_dz); - if is_stair_legacy(back_neighbor.0) { - let back_facing = get_stair_facing(back_neighbor.1); - let back_half = if (back_neighbor.1 & STAIR_UPSIDE_DOWN_BIT) != 0 { - "top" - } else { - "bottom" - }; - if back_half == half { - if let Some(side) = get_relative_side(facing, &back_facing) { - properties.insert("shape".to_string(), format!("outer_{}", side)); - } - } - } else { - let front_neighbor = get_neighbor(x as i32 + front_dx, global_y as i32, z as i32 + front_dz); - if is_stair_legacy(front_neighbor.0) { - let front_facing = get_stair_facing(front_neighbor.1); - let front_half = if (front_neighbor.1 & STAIR_UPSIDE_DOWN_BIT) != 0 { - "top" - } else { - "bottom" - }; - if front_half == half { - if let Some(side) = get_relative_side(facing, &front_facing) { - properties.insert("shape".to_string(), format!("inner_{}", side)); - } - } - } - } - properties_changed = true; - } else if is_fence_legacy(block_id) { - let (n_id, _) = get_neighbor(x as i32, global_y as i32, z as i32 - 1); - let (e_id, _) = get_neighbor(x as i32 + 1, global_y as i32, z as i32); - let (s_id, _) = get_neighbor(x as i32, global_y as i32, z as i32 + 1); - let (w_id, _) = get_neighbor(x as i32 - 1, global_y as i32, z as i32); - properties.insert( - "north".to_string(), - (is_fence_legacy(n_id) || is_fence_gate_legacy(n_id) || is_likely_solid_attachment(n_id)) - .to_string(), - ); - properties.insert( - "east".to_string(), - (is_fence_legacy(e_id) || is_fence_gate_legacy(e_id) || is_likely_solid_attachment(e_id)) - .to_string(), - ); - properties.insert( - "south".to_string(), - (is_fence_legacy(s_id) || is_fence_gate_legacy(s_id) || is_likely_solid_attachment(s_id)) - .to_string(), - ); - properties.insert( - "west".to_string(), - (is_fence_legacy(w_id) || is_fence_gate_legacy(w_id) || is_likely_solid_attachment(w_id)) - .to_string(), - ); - properties_changed = true; - } else if is_pane_legacy(block_id) { - let (n_id, _) = get_neighbor(x as i32, global_y as i32, z as i32 - 1); - let (e_id, _) = get_neighbor(x as i32 + 1, global_y as i32, z as i32); - let (s_id, _) = get_neighbor(x as i32, global_y as i32, z as i32 + 1); - let (w_id, _) = get_neighbor(x as i32 - 1, global_y as i32, z as i32); - properties.insert( - "north".to_string(), - (is_pane_legacy(n_id) || is_glass_legacy(n_id) || is_likely_solid_attachment(n_id)) - .to_string(), - ); - properties.insert( - "east".to_string(), - (is_pane_legacy(e_id) || is_glass_legacy(e_id) || is_likely_solid_attachment(e_id)) - .to_string(), - ); - properties.insert( - "south".to_string(), - (is_pane_legacy(s_id) || is_glass_legacy(s_id) || is_likely_solid_attachment(s_id)) - .to_string(), - ); - properties.insert( - "west".to_string(), - (is_pane_legacy(w_id) || is_glass_legacy(w_id) || is_likely_solid_attachment(w_id)) - .to_string(), - ); - properties_changed = true; - } - - if properties_changed || name == "minecraft:red_bed" { - if !properties.is_empty() { - let parts: Vec = properties.iter().map(|(k, v)| format!("{}={}", k, v)).collect(); - return format!("{}[{}]", name, parts.join(",")); - } - return name.to_string(); - } - - modern_state -} - -fn get_modern_block_name(block_id: u8, meta: u8) -> String { - let name = get_contextual_modern_name(block_id, meta); - if let Some(props) = get_contextual_properties(block_id, meta) { - format!("{}[{}]", name, props) - } else { - name - } -} - -fn get_contextual_modern_name(block_id: u8, meta: u8) -> String { - match block_id { - 0 => "minecraft:air".into(), - 1 => "minecraft:stone".into(), - 2 => "minecraft:grass_block".into(), - 3 => "minecraft:dirt".into(), - 4 => "minecraft:cobblestone".into(), - 5 => match meta { - 1 => "minecraft:spruce_planks", - 2 => "minecraft:birch_planks", - 3 => "minecraft:jungle_planks", - _ => "minecraft:oak_planks", - } - .into(), - 6 => match meta { - 1 => "minecraft:spruce_sapling", - 2 => "minecraft:birch_sapling", - 3 => "minecraft:jungle_sapling", - _ => "minecraft:oak_sapling", - } - .into(), - 7 => "minecraft:bedrock".into(), - 8 | 9 => "minecraft:water".into(), - 10 | 11 => "minecraft:lava".into(), - 12 => "minecraft:sand".into(), - 13 => "minecraft:gravel".into(), - 14 => "minecraft:gold_ore".into(), - 15 => "minecraft:iron_ore".into(), - 16 => "minecraft:coal_ore".into(), - 17 => match meta & 3 { - 1 => "minecraft:spruce_log", - 2 => "minecraft:birch_log", - 3 => "minecraft:jungle_log", - _ => "minecraft:oak_log", - } - .into(), - 18 => match meta & 3 { - 1 => "minecraft:spruce_leaves", - 2 => "minecraft:birch_leaves", - 3 => "minecraft:jungle_leaves", - _ => "minecraft:oak_leaves", - } - .into(), - 19 => "minecraft:sponge".into(), - 20 => "minecraft:glass".into(), - 21 => "minecraft:lapis_ore".into(), - 22 => "minecraft:lapis_block".into(), - 23 => "minecraft:dispenser".into(), - 24 => match meta { - 1 => "minecraft:chiseled_sandstone", - 2 => "minecraft:smooth_sandstone", - _ => "minecraft:sandstone", - } - .into(), - 25 => "minecraft:note_block".into(), - 26 => "minecraft:red_bed".into(), - 27 => "minecraft:powered_rail".into(), - 28 => "minecraft:detector_rail".into(), - 29 => "minecraft:sticky_piston".into(), - 30 => "minecraft:cobweb".into(), - 31 => "minecraft:short_grass".into(), - 32 => "minecraft:dead_bush".into(), - 33 => "minecraft:piston".into(), - 35 => match meta { - 1 => "minecraft:orange_wool", - 2 => "minecraft:magenta_wool", - 3 => "minecraft:light_blue_wool", - 4 => "minecraft:yellow_wool", - 5 => "minecraft:lime_wool", - 6 => "minecraft:pink_wool", - 7 => "minecraft:gray_wool", - 8 => "minecraft:light_gray_wool", - 9 => "minecraft:cyan_wool", - 10 => "minecraft:purple_wool", - 11 => "minecraft:blue_wool", - 12 => "minecraft:brown_wool", - 13 => "minecraft:green_wool", - 14 => "minecraft:red_wool", - 15 => "minecraft:black_wool", - _ => "minecraft:white_wool", - } - .into(), - 37 => "minecraft:dandelion".into(), - 38 => "minecraft:poppy".into(), - 39 => "minecraft:brown_mushroom".into(), - 40 => "minecraft:red_mushroom".into(), - 41 => "minecraft:gold_block".into(), - 42 => "minecraft:iron_block".into(), - 44 => { - let variant = meta & 7; - let name = match variant { - 1 => "minecraft:sandstone_slab", - 2 => "minecraft:stone_slab", - 3 => "minecraft:cobblestone_slab", - 4 => "minecraft:brick_slab", - 5 => "minecraft:stone_brick_slab", - 6 => "minecraft:nether_brick_slab", - 7 => "minecraft:quartz_slab", - _ => "minecraft:stone_slab", - }; - return name.to_string(); - } - 45 => "minecraft:bricks".into(), - 46 => "minecraft:tnt".into(), - 47 => "minecraft:bookshelf".into(), - 48 => "minecraft:mossy_cobblestone".into(), - 49 => "minecraft:obsidian".into(), - 50 => "minecraft:torch".into(), - 51 => "minecraft:fire".into(), - 52 => "minecraft:mob_spawner".into(), - 53 => "minecraft:oak_stairs".into(), - 54 => "minecraft:chest".into(), - 55 => "minecraft:redstone_wire".into(), - 56 => "minecraft:diamond_ore".into(), - 57 => "minecraft:diamond_block".into(), - 58 => "minecraft:crafting_table".into(), - 59 => "minecraft:wheat".into(), - 60 => "minecraft:farmland".into(), - 61 => "minecraft:furnace".into(), - 63 => "minecraft:oak_sign".into(), - 64 => "minecraft:oak_door".into(), - 65 => "minecraft:ladder".into(), - 66 => "minecraft:rail".into(), - 67 => "minecraft:cobblestone_stairs".into(), - 68 => "minecraft:oak_wall_sign".into(), - 69 => "minecraft:lever".into(), - 70 => "minecraft:stone_pressure_plate".into(), - 71 => "minecraft:iron_door".into(), - 72 => "minecraft:oak_pressure_plate".into(), - 73 => "minecraft:redstone_ore".into(), - 75 => "minecraft:redstone_wall_torch".into(), - 76 => "minecraft:redstone_torch".into(), - 77 => "minecraft:stone_button".into(), - 78 => "minecraft:snow".into(), - 79 => "minecraft:ice".into(), - 80 => "minecraft:snow_block".into(), - 81 => "minecraft:cactus".into(), - 82 => "minecraft:clay".into(), - 83 => "minecraft:sugar_cane".into(), - 84 => "minecraft:jukebox".into(), - 85 => "minecraft:oak_fence".into(), - 86 => "minecraft:carved_pumpkin".into(), - 87 => "minecraft:netherrack".into(), - 88 => "minecraft:soul_sand".into(), - 89 => "minecraft:glowstone".into(), - 90 => "minecraft:nether_portal".into(), - 91 => "minecraft:jack_o_lantern".into(), - 92 => "minecraft:cake".into(), - 93 => "minecraft:unpowered_repeater".into(), - 94 => "minecraft:powered_repeater".into(), - 96 => "minecraft:trapdoor".into(), - 98 => "minecraft:stone_bricks".into(), - 101 => "minecraft:iron_bars".into(), - 102 => "minecraft:glass_pane".into(), - 103 => "minecraft:melon".into(), - 104 => "minecraft:pumpkin_stem".into(), - 105 => "minecraft:melon_stem".into(), - 106 => "minecraft:vine".into(), - 107 => "minecraft:oak_fence_gate".into(), - 108 => "minecraft:brick_stairs".into(), - 109 => "minecraft:stone_brick_stairs".into(), - 110 => "minecraft:mycelium".into(), - 111 => "minecraft:lily_pad".into(), - 112 => "minecraft:nether_bricks".into(), - 113 => "minecraft:nether_brick_fence".into(), - 114 => "minecraft:nether_brick_stairs".into(), - 115 => "minecraft:nether_wart".into(), - 116 => "minecraft:enchanting_table".into(), - 117 => "minecraft:brewing_stand".into(), - 118 => "minecraft:cauldron".into(), - 121 => "minecraft:end_stone".into(), - 122 => "minecraft:dragon_egg".into(), - 123 => "minecraft:redstone_lamp".into(), - 124 => "minecraft:redstone_lamp".into(), - 125 => "minecraft:double_wooden_slab".into(), - 126 => "minecraft:wooden_slab".into(), - 127 => "minecraft:cocoa".into(), - 128 => "minecraft:sandstone_stairs".into(), - 129 => "minecraft:emerald_ore".into(), - 130 => "minecraft:ender_chest".into(), - 131 => "minecraft:tripwire_hook".into(), - 132 => "minecraft:tripwire".into(), - 133 => "minecraft:emerald_block".into(), - 134 => "minecraft:spruce_stairs".into(), - 135 => "minecraft:birch_stairs".into(), - 136 => "minecraft:jungle_stairs".into(), - 138 => "minecraft:beacon".into(), - 139 => "minecraft:cobblestone_wall".into(), - 140 => "minecraft:flower_pot".into(), - 141 => "minecraft:carrots".into(), - 142 => "minecraft:potatoes".into(), - 143 => "minecraft:wooden_button".into(), - 144 => "minecraft:skull".into(), - 145 => "minecraft:anvil".into(), - 146 => "minecraft:trapped_chest".into(), - 147 => "minecraft:light_weighted_pressure_plate".into(), - 148 => "minecraft:heavy_weighted_pressure_plate".into(), - 149 => "minecraft:unpowered_comparator".into(), - 150 => "minecraft:powered_comparator".into(), - 151 => "minecraft:daylight_detector".into(), - 152 => "minecraft:redstone_block".into(), - 153 => "minecraft:nether_quartz_ore".into(), - 154 => "minecraft:hopper".into(), - 155 => match meta { - 1 => "minecraft:chiseled_quartz_block", - 2 => "minecraft:quartz_pillar", - 3 => "minecraft:quartz_pillar", - _ => "minecraft:quartz_block", - } - .into(), - 156 => "minecraft:quartz_stairs".into(), - 157 => "minecraft:activator_rail".into(), - 158 => "minecraft:dropper".into(), - 159 => match meta { - 0 => "minecraft:white_stained_hardened_clay", - 1 => "minecraft:orange_stained_hardened_clay", - 2 => "minecraft:magenta_stained_hardened_clay", - 3 => "minecraft:light_blue_stained_hardened_clay", - 4 => "minecraft:yellow_stained_hardened_clay", - 5 => "minecraft:lime_stained_hardened_clay", - 6 => "minecraft:pink_stained_hardened_clay", - 7 => "minecraft:gray_stained_hardened_clay", - 8 => "minecraft:light_gray_stained_hardened_clay", - 9 => "minecraft:cyan_stained_hardened_clay", - 10 => "minecraft:purple_stained_hardened_clay", - 11 => "minecraft:blue_stained_hardened_clay", - 12 => "minecraft:brown_stained_hardened_clay", - 13 => "minecraft:green_stained_hardened_clay", - 14 => "minecraft:red_stained_hardened_clay", - 15 => "minecraft:black_stained_hardened_clay", - _ => "minecraft:white_stained_hardened_clay", - } - .into(), - 160 => match meta { - 0 => "minecraft:white_stained_glass_pane", - 1 => "minecraft:orange_stained_glass_pane", - 2 => "minecraft:magenta_stained_glass_pane", - 3 => "minecraft:light_blue_stained_glass_pane", - 4 => "minecraft:yellow_stained_glass_pane", - 5 => "minecraft:lime_stained_glass_pane", - 6 => "minecraft:pink_stained_glass_pane", - 7 => "minecraft:gray_stained_glass_pane", - 8 => "minecraft:light_gray_stained_glass_pane", - 9 => "minecraft:cyan_stained_glass_pane", - 10 => "minecraft:purple_stained_glass_pane", - 11 => "minecraft:blue_stained_glass_pane", - 12 => "minecraft:brown_stained_glass_pane", - 13 => "minecraft:green_stained_glass_pane", - 14 => "minecraft:red_stained_glass_pane", - 15 => "minecraft:black_stained_glass_pane", - _ => "minecraft:white_stained_glass_pane", - } - .into(), - 161 => match meta & 3 { - 1 => "minecraft:acacia_leaves", - _ => "minecraft:dark_oak_leaves", - } - .into(), - 162 => match meta & 3 { - 1 => "minecraft:acacia_log", - _ => "minecraft:dark_oak_log", - } - .into(), - 163 => "minecraft:acacia_stairs".into(), - 164 => "minecraft:dark_oak_stairs".into(), - 170 => "minecraft:hay_block".into(), - 171 => match meta { - 0 => "minecraft:white_carpet", - 1 => "minecraft:orange_carpet", - 2 => "minecraft:magenta_carpet", - 3 => "minecraft:light_blue_carpet", - 4 => "minecraft:yellow_carpet", - 5 => "minecraft:lime_carpet", - 6 => "minecraft:pink_carpet", - 7 => "minecraft:gray_carpet", - 8 => "minecraft:light_gray_carpet", - 9 => "minecraft:cyan_carpet", - 10 => "minecraft:purple_carpet", - 11 => "minecraft:blue_carpet", - 12 => "minecraft:brown_carpet", - 13 => "minecraft:green_carpet", - 14 => "minecraft:red_carpet", - 15 => "minecraft:black_carpet", - _ => "minecraft:white_carpet", - } - .into(), - 172 => match meta { - 0 => "minecraft:white_concrete", - 1 => "minecraft:orange_concrete", - 2 => "minecraft:magenta_concrete", - 3 => "minecraft:light_blue_concrete", - 4 => "minecraft:yellow_concrete", - 5 => "minecraft:lime_concrete", - 6 => "minecraft:pink_concrete", - 7 => "minecraft:gray_concrete", - 8 => "minecraft:light_gray_concrete", - 9 => "minecraft:cyan_concrete", - 10 => "minecraft:purple_concrete", - 11 => "minecraft:blue_concrete", - 12 => "minecraft:brown_concrete", - 13 => "minecraft:green_concrete", - 14 => "minecraft:red_concrete", - 15 => "minecraft:black_concrete", - _ => "minecraft:white_concrete", - } - .into(), - 173 => "minecraft:coal_block".into(), - 95 => match meta { - 0 => "minecraft:white_stained_glass", - 1 => "minecraft:orange_stained_glass", - 2 => "minecraft:magenta_stained_glass", - 3 => "minecraft:light_blue_stained_glass", - 4 => "minecraft:yellow_stained_glass", - 5 => "minecraft:lime_stained_glass", - 6 => "minecraft:pink_stained_glass", - 7 => "minecraft:gray_stained_glass", - 8 => "minecraft:light_gray_stained_glass", - 9 => "minecraft:cyan_stained_glass", - 10 => "minecraft:purple_stained_glass", - 11 => "minecraft:blue_stained_glass", - 12 => "minecraft:brown_stained_glass", - 13 => "minecraft:green_stained_glass", - 14 => "minecraft:red_stained_glass", - 15 => "minecraft:black_stained_glass", - _ => "minecraft:white_stained_glass", - } - .into(), - _ => "minecraft:air".into(), - } -} - -fn get_contextual_properties(block_id: u8, meta: u8) -> Option { - match block_id { - 63 => Some(format!("rotation={}", meta & 0x0F)), - 68 => Some(format!( - "facing={}", - match meta { - 2 => "north", - 3 => "south", - 4 => "west", - _ => "east", - } - )), - 50 | 75 | 76 => { - if meta >= 1 && meta <= 4 { - Some(format!( - "facing={}", - match meta { - 1 => "east", - 2 => "west", - 3 => "south", - _ => "north", - } - )) - } else { - None - } - } - _ => None, - } -} - -fn is_stair_legacy(id: u8) -> bool { - matches!( - id, - 53 | 67 | 108 | 109 | 114 | 128 | 134 | 135 | 136 | 156 | 163 | 164 | 180 - ) -} - -fn get_stair_facing(meta: u8) -> &'static str { - match meta & 0x3 { - 0 => "east", - 1 => "west", - 2 => "south", - 3 => "north", - _ => "north", - } -} - -fn get_relative_side(current_facing: &str, neighbor_facing: &str) -> Option<&'static str> { - match current_facing { - "north" => { - if neighbor_facing == "west" { - return Some("left"); - } - if neighbor_facing == "east" { - return Some("right"); - } - } - "south" => { - if neighbor_facing == "east" { - return Some("left"); - } - if neighbor_facing == "west" { - return Some("right"); - } - } - "west" => { - if neighbor_facing == "south" { - return Some("left"); - } - if neighbor_facing == "north" { - return Some("right"); - } - } - "east" => { - if neighbor_facing == "north" { - return Some("left"); - } - if neighbor_facing == "south" { - return Some("right"); - } - } - _ => {} - } - None -} - -fn is_fence_legacy(id: u8) -> bool { - matches!(id, 85 | 113 | 188 | 189 | 190 | 191 | 192) -} - -fn is_fence_gate_legacy(id: u8) -> bool { - matches!(id, 107 | 183 | 184 | 185 | 186 | 187) -} - -fn is_pane_legacy(id: u8) -> bool { - matches!(id, 101 | 102 | 160) -} - -fn is_glass_legacy(id: u8) -> bool { - matches!(id, 20 | 95) -} - -fn is_likely_solid_attachment(id: u8) -> bool { - if id == 0 { - return false; - } - if id >= 8 && id <= 11 { - return false; - } - !matches!( - id, - 6 | 27 | 28 | 30 | 31 | 32 | 37 | 38 | 39 | 40 | 50 | 51 | 55 | 59 | 63 | 65 | 66 - | 68 | 69 | 70 | 71 | 72 | 75 | 76 | 77 | 78 | 83 | 90 | 92 | 93 | 94 | 96 | 101 - | 102 | 104 | 105 | 106 | 107 | 111 | 115 | 119 | 127 | 131 | 132 | 141 | 142 | 143 - | 147 | 148 | 149 | 150 | 157 | 160 | 171 | 175 - ) -} diff --git a/src-tauri/src/commands/java2lce/level_dat.rs b/src-tauri/src/commands/java2lce/level_dat.rs deleted file mode 100644 index 2455b74..0000000 --- a/src-tauri/src/commands/java2lce/level_dat.rs +++ /dev/null @@ -1,261 +0,0 @@ -use super::nbt::{self, NbtCompound, NbtValue}; -pub struct SpawnPoint { - pub x: i32, - pub y: i32, - pub z: i32, -} - -pub fn read_spawn(root: &NbtCompound) -> SpawnPoint { - let data = match root.compound("Data") { - Some(d) => d, - None => { - return SpawnPoint { x: 0, y: 64, z: 0 }; - } - }; - - if let (Some(sx), Some(sz)) = (data.int("SpawnX"), data.int("SpawnZ")) { - return SpawnPoint { - x: sx, - y: data.int("SpawnY").unwrap_or(64), - z: sz, - }; - } - - if let Some(spawn_comp) = data.compound("spawn") { - if let Some(pos) = spawn_comp.int_array("pos") { - if pos.len() >= 3 { - return SpawnPoint { - x: pos[0], - y: pos[1], - z: pos[2], - }; - } - } - } - - SpawnPoint { x: 0, y: 64, z: 0 } -} - -pub fn convert_java_to_lce( - java_root: &NbtCompound, - spawn_chunk_x: i32, - spawn_chunk_z: i32, - xz_size: i32, - flat_world: bool, - override_spawn_y: Option, -) -> Vec { - let java_data = java_root - .compound("Data") - .expect("Java level.dat missing 'Data' compound tag"); - - let data_version = java_data - .int("DataVersion") - .or_else(|| java_root.int("DataVersion")) - .unwrap_or(0); - let is_modern_world = data_version >= 1519; - let hell_scale: i32 = 3; - let spawn = read_spawn(java_root); - let spawn_x = spawn.x; - let spawn_y = if let Some(oy) = override_spawn_y { - oy.clamp(1, 127) - } else if is_modern_world { - 64 - } else { - spawn.y.clamp(1, 127) - }; - let spawn_z = spawn.z; - let new_spawn_x = spawn_x - (spawn_chunk_x * 16); - let new_spawn_z = spawn_z - (spawn_chunk_z * 16); - let safe_generator_name = if flat_world { - "flat".to_string() - } else if is_modern_world { - "default".to_string() - } else { - let name = get_string(java_data, "generatorName", "default"); - match name.as_str() { - "flat" | "superflat" => "flat".to_string(), - "largeBiomes" => "largeBiomes".to_string(), - _ => "default".to_string(), - } - }; - let safe_generator_version = if flat_world { - 0 - } else if is_modern_world { - 1 - } else { - let version = get_int(java_data, "generatorVersion"); - if safe_generator_name == "default" { - 1 - } else { - version - } - }; - let safe_generator_options = if flat_world { - get_string(java_data, "generatorOptions", "2;7,2x3,2;1;") - } else if is_modern_world { - "".to_string() - } else { - get_string(java_data, "generatorOptions", "") - }; - - let mut lce_data = NbtCompound::new("Data"); - lce_data.insert("RandomSeed", NbtValue::Long(get_long(java_data, "RandomSeed"))); - lce_data.insert("generatorName", NbtValue::String(safe_generator_name)); - lce_data.insert("generatorVersion", NbtValue::Int(safe_generator_version)); - lce_data.insert("generatorOptions", NbtValue::String(safe_generator_options)); - lce_data.insert("GameType", NbtValue::Int(get_int(java_data, "GameType"))); - lce_data.insert("MapFeatures", NbtValue::Byte(get_bool(java_data, "MapFeatures", true))); - lce_data.insert("SpawnX", NbtValue::Int(new_spawn_x)); - lce_data.insert("SpawnY", NbtValue::Int(spawn_y)); - lce_data.insert("SpawnZ", NbtValue::Int(new_spawn_z)); - lce_data.insert("Time", NbtValue::Long(get_long(java_data, "Time"))); - lce_data.insert("DayTime", NbtValue::Long(get_long(java_data, "DayTime"))); - lce_data.insert("SizeOnDisk", NbtValue::Long(0)); - lce_data.insert("LastPlayed", NbtValue::Long(unix_timestamp_millis())); - lce_data.insert( - "LevelName", - NbtValue::String(get_string(java_data, "LevelName", "Converted World")), - ); - lce_data.insert("version", NbtValue::Int(19133)); - lce_data.insert("rainTime", NbtValue::Int(get_int(java_data, "rainTime"))); - lce_data.insert("raining", NbtValue::Byte(get_bool(java_data, "raining", false))); - lce_data.insert("thunderTime", NbtValue::Int(get_int(java_data, "thunderTime"))); - lce_data.insert( - "thundering", - NbtValue::Byte(get_bool(java_data, "thundering", false)), - ); - lce_data.insert( - "hardcore", - NbtValue::Byte(get_bool(java_data, "hardcore", false)), - ); - lce_data.insert( - "allowCommands", - NbtValue::Byte(get_bool(java_data, "allowCommands", false)), - ); - lce_data.insert( - "initialized", - NbtValue::Byte(get_bool(java_data, "initialized", true)), - ); - - lce_data.insert("newSeaLevel", NbtValue::Byte(1)); - lce_data.insert( - "hasBeenInCreative", - NbtValue::Byte(get_bool(java_data, "hasBeenInCreative", false)), - ); - lce_data.insert( - "spawnBonusChest", - NbtValue::Byte(get_bool(java_data, "spawnBonusChest", false)), - ); - - lce_data.insert("hasStronghold", NbtValue::Byte(0)); - lce_data.insert("StrongholdX", NbtValue::Int(0)); - lce_data.insert("StrongholdY", NbtValue::Int(0)); - lce_data.insert("StrongholdZ", NbtValue::Int(0)); - lce_data.insert("hasStrongholdEndPortal", NbtValue::Byte(0)); - lce_data.insert("StrongholdEndPortalX", NbtValue::Int(0)); - lce_data.insert("StrongholdEndPortalZ", NbtValue::Int(0)); - lce_data.insert("XZSize", NbtValue::Int(xz_size)); - lce_data.insert("HellScale", NbtValue::Int(hell_scale)); - if !is_modern_world { - if let Some(game_rules) = java_data.get("GameRules") { - lce_data.insert("GameRules", game_rules.clone()); - } - } - - let mut root = NbtCompound::new(""); - root.insert("Data", NbtValue::Compound(lce_data)); - nbt::write_nbt(&root) -} - -pub fn convert_lce_to_java( - lce_root: &NbtCompound, - override_spawn_x: Option, - override_spawn_y: Option, - override_spawn_z: Option, - embedded_player: Option<&NbtCompound>, -) -> Vec { - let lce_data = lce_root.compound("Data").unwrap_or(lce_root); - let mut java_data = lce_data.clone(); - let lce_only_fields = [ - "newSeaLevel", - "hasBeenInCreative", - "spawnBonusChest", - "XZSize", - "xzSize", - "HellScale", - "hellScale", - "hasStronghold", - "StrongholdX", - "StrongholdY", - "StrongholdZ", - "hasStrongholdEndPortal", - "StrongholdEndPortalX", - "StrongholdEndPortalZ", - "xStronghold", - "yStronghold", - "zStronghold", - "hasStrongholdEP", - "xStrongholdEP", - "zStrongholdEP", - ]; - - for field in lce_only_fields { - java_data.remove(field); - } - - if let Some(sx) = override_spawn_x { - java_data.insert("SpawnX", NbtValue::Int(sx)); - } - if let Some(sy) = override_spawn_y { - java_data.insert("SpawnY", NbtValue::Int(sy)); - } - if let Some(sz) = override_spawn_z { - java_data.insert("SpawnZ", NbtValue::Int(sz)); - } - - java_data.insert("version", NbtValue::Int(19133)); - java_data.insert("DataVersion", NbtValue::Int(1343)); - let mut version_compound = NbtCompound::new("Version"); - version_compound.insert("Id", NbtValue::Int(1343)); - version_compound.insert("Name", NbtValue::String("1.12.2".to_string())); - version_compound.insert("Snapshot", NbtValue::Byte(0)); - java_data.insert("Version", NbtValue::Compound(version_compound)); - if let Some(player) = embedded_player { - let mut player_tag = player.clone(); - player_tag.name = "Player".to_string(); - java_data.insert("Player", NbtValue::Compound(player_tag)); - } - - java_data.insert("LastPlayed", NbtValue::Long(unix_timestamp_millis())); - let mut java_root = NbtCompound::new(""); - let mut data_tag = NbtCompound::new("Data"); - for (name, value) in &java_data.tags { - data_tag.insert(name, value.clone()); - } - java_root.insert("Data", NbtValue::Compound(data_tag)); - - nbt::write_gzip_nbt(&java_root) -} - -fn get_long(compound: &NbtCompound, name: &str) -> i64 { - compound.long(name).unwrap_or(0) -} - -fn get_int(compound: &NbtCompound, name: &str) -> i32 { - compound.int(name).unwrap_or(0) -} - -fn get_string(compound: &NbtCompound, name: &str, default: &str) -> String { - compound.string(name).unwrap_or(default).to_string() -} - -fn get_bool(compound: &NbtCompound, name: &str, default: bool) -> i8 { - compound.byte(name).unwrap_or(if default { 1 } else { 0 }) -} - -fn unix_timestamp_millis() -> i64 { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as i64 -} diff --git a/src-tauri/src/commands/java2lce/mod.rs b/src-tauri/src/commands/java2lce/mod.rs deleted file mode 100644 index b64c5fd..0000000 --- a/src-tauri/src/commands/java2lce/mod.rs +++ /dev/null @@ -1,404 +0,0 @@ -pub mod block_mapping; -pub mod chunk; -pub mod payload; -pub mod level_dat; -pub mod nbt; -pub mod region; -use std::fs; -use std::path::Path; -use tauri::AppHandle; -use std::collections::HashMap; -use region::{JavaWorldReader, JavaRegionFileWriter, LceRegionFile, SaveDataContainer}; -use chunk::{convert_chunk, build_modern_anvil_level}; -use level_dat::{read_spawn, convert_java_to_lce, convert_lce_to_java}; -const DEFAULT_XZ_SIZE: i32 = 54; -fn floor_div(a: i32, b: i32) -> i32 { - let q = a / b; - let r = a % b; - if r != 0 && ((r < 0) != (b < 0)) { - q - 1 - } else { - q - } -} -fn estimate_safe_spawn_y( - reader: &mut JavaWorldReader, - spawn_x: i32, - source_spawn_y: i32, - spawn_z: i32, - spawn_chunk_x: i32, - spawn_chunk_z: i32, -) -> Option { - let region_x = floor_div(spawn_chunk_x, 32); - let region_z = floor_div(spawn_chunk_z, 32); - let region_path = reader - .get_region_files("") - .into_iter() - .find(|(rx, rz, _)| *rx == region_x && *rz == region_z) - .map(|(_, _, path)| path)?; - - let local_chunk_x = ((spawn_chunk_x % 32) + 32) % 32; - let local_chunk_z = ((spawn_chunk_z % 32) + 32) % 32; - let root = match reader.read_chunk_nbt(®ion_path, local_chunk_x, local_chunk_z) { - Ok(Some(r)) => r, - _ => return None, - }; - - let level = root.compound("Level").unwrap_or(&root); - let lx = ((spawn_x % 16) + 16) % 16; - let lz = ((spawn_z % 16) + 16) % 16; - let idx2d = (lx + lz * 16) as usize; - if let Some(hm) = level.byte_array("HeightMap") { - if hm.len() >= 256 { - let height = hm[idx2d]; - if height > 0 { - return Some((height as i32 + 1).clamp(1, 127)); - } - } - } - - if let Some(hm) = level.int_array("HeightMap") { - if hm.len() >= 256 { - let height = hm[idx2d]; - if height > 0 { - return Some((height + 1).clamp(1, 127)); - } - } - } - - if let Some(blocks) = level.byte_array("Blocks") { - if blocks.len() >= 32768 { - for y in (1..=127).rev() { - let flat_index = (y * 256 + lz * 16 + lx) as usize; - if blocks[flat_index] != 0 { - return Some((y + 1).clamp(1, 127)); - } - } - } - } - - if let Some(sections) = level.list("Sections").or_else(|| level.list("sections")) { - let mut max_y = -1; - for tag in sections { - if let nbt::NbtValue::Compound(section) = tag { - let section_y = match chunk::read_section_y(section) { - Some(y) if (0..=7).contains(&y) => y, - _ => continue, - }; - if let Some(section_blocks) = section.byte_array("Blocks") { - if section_blocks.len() >= 4096 { - for y in (0..=15).rev() { - let index = (lx + lz * 16 + y * 256) as usize; - if section_blocks[index] != 0 { - let global_y = section_y * 16 + y; - if global_y > max_y { - max_y = global_y; - } - break; - } - } - } - } - } - } - if max_y >= 0 { - return Some((max_y + 1).clamp(1, 127)); - } - } - - Some(source_spawn_y.clamp(1, 127)) -} - -fn convert_dimension( - reader: &mut JavaWorldReader, - container: &mut SaveDataContainer, - dimension: &str, - half_size: i32, - offset_chunk_x: i32, - offset_chunk_z: i32, - global_section_shift: &mut Option, - errors: &mut Vec, -) -> usize { - let region_files = reader.get_region_files(dimension); - let region_lookup: HashMap<(i32, i32), String> = region_files - .into_iter() - .map(|(rx, rz, path)| ((rx, rz), path)) - .collect(); - - let lce_prefix = match dimension { - "DIM-1" => "DIM-1", - "DIM1" => "DIM1/", - _ => "", - }; - - let mut lce_regions: HashMap<(i32, i32), LceRegionFile> = HashMap::new(); - let mut converted = 0usize; - for lcx in -half_size..half_size { - for lcz in -half_size..half_size { - let jx = lcx + offset_chunk_x; - let jz = lcz + offset_chunk_z; - let jrx = floor_div(jx, 32); - let jrz = floor_div(jz, 32); - let region_path = match region_lookup.get(&(jrx, jrz)) { - Some(p) => p, - None => continue, - }; - let local_x = ((jx % 32) + 32) % 32; - let local_z = ((jz % 32) + 32) % 32; - let root = match reader.read_chunk_nbt(region_path, local_x, local_z) { - Ok(Some(r)) => r, - Ok(None) => continue, - Err(e) => { - errors.push(format!("{} ({},{}): {}", dimension, lcx, lcz, e)); - continue; - } - }; - - let payload = convert_chunk(&root, lcx, lcz, false, global_section_shift); - if payload.is_empty() { - continue; - } - - let lrx = floor_div(lcx, 32); - let lrz = floor_div(lcz, 32); - let lce_local_x = ((lcx % 32) + 32) % 32; - let lce_local_z = ((lcz % 32) + 32) % 32; - let region = lce_regions.entry((lrx, lrz)).or_insert_with(|| { - LceRegionFile::new(&format!("{}r.{}.{}.mcr", lce_prefix, lrx, lrz)) - }); - region.write_chunk(lce_local_x, lce_local_z, payload); - converted += 1; - } - } - - for (_, region) in lce_regions.iter_mut() { - region.write_to_container(container); - } - - converted -} -#[tauri::command] -#[allow(non_snake_case)] -pub async fn java_to_lce( - _app: AppHandle, - java_world_path: String, - output_ms_path: String, -) -> Result { - let mut reader = JavaWorldReader::new(&java_world_path); - let java_root = reader.read_level_dat().map_err(|e| format!("Failed to read level.dat: {}", e))?; - let spawn = read_spawn(&java_root); - let spawn_chunk_x = spawn.x >> 4; - let spawn_chunk_z = spawn.z >> 4; - let xz_size = DEFAULT_XZ_SIZE; - let half_size = xz_size / 2; - let hell_scale = 3; - let hell_half_size = (xz_size / hell_scale) / 2; - let end_half_size = 9; - let mut container = SaveDataContainer::new(7, 9); - let default_region_order = [ - "DIM-1r.-1.-1.mcr", "DIM-1r.0.-1.mcr", "DIM-1r.0.0.mcr", "DIM-1r.-1.0.mcr", - "DIM1/r.-1.-1.mcr", "DIM1/r.0.-1.mcr", "DIM1/r.0.0.mcr", "DIM1/r.-1.0.mcr", - "r.-1.-1.mcr", "r.0.-1.mcr", "r.0.0.mcr", "r.-1.0.mcr", - ]; - for name in default_region_order { - container.create_file(name); - } - - let estimated_spawn_y = estimate_safe_spawn_y( - &mut reader, - spawn.x, - spawn.y, - spawn.z, - spawn_chunk_x, - spawn_chunk_z, - ); - - let mut global_section_shift: Option = None; - let mut errors: Vec = Vec::new(); - let ow = convert_dimension( - &mut reader, - &mut container, - "", - half_size, - spawn_chunk_x, - spawn_chunk_z, - &mut global_section_shift, - &mut errors, - ); - let nether = convert_dimension( - &mut reader, - &mut container, - "DIM-1", - hell_half_size, - floor_div(spawn_chunk_x, 8), - floor_div(spawn_chunk_z, 8), - &mut global_section_shift, - &mut errors, - ); - let end = convert_dimension( - &mut reader, - &mut container, - "DIM1", - end_half_size, - 0, - 0, - &mut global_section_shift, - &mut errors, - ); - - let level_dat_bytes = convert_java_to_lce( - &java_root, - spawn_chunk_x, - spawn_chunk_z, - xz_size, - false, - estimated_spawn_y, - ); - let ld_idx = container.create_file("level.dat"); - container.write_to_file(ld_idx, &level_dat_bytes); - container.save(&output_ms_path).map_err(|e| format!("Failed to save output: {}", e))?; - let chunks_written = ow + nether + end; - let mut msg = format!( - "Conversion complete!\nChunks: {}\nOverworld: {}\nNether: {}\nEnd: {}", - chunks_written, ow, nether, end - ); - if !errors.is_empty() { - msg.push_str(&format!("\nErrors: {}", errors.len())); - for err in errors.iter().take(5) { - msg.push_str(&format!("\n {}", err)); - } - if errors.len() > 5 { - msg.push_str(&format!("\n ... and {} more", errors.len() - 5)); - } - } - eprintln!("{}",msg); - Ok(msg) -} - -#[tauri::command] -#[allow(non_snake_case)] -pub async fn lce_to_java( - _app: AppHandle, - input_ms_path: String, - java_world_output: String, -) -> Result { - let ms_data = fs::read(&input_ms_path).map_err(|e| format!("Failed to read saveData.ms: {}", e))?; - let decompressed = region::decompress_zlib(&ms_data[8..]).map_err(|e| format!("Failed to decompress save data: {}", e))?; - let footer_offset = u32::from_le_bytes([ - decompressed[0], decompressed[1], decompressed[2], decompressed[3], - ]) as usize; - let entry_count = u32::from_le_bytes([ - decompressed[4], decompressed[5], decompressed[6], decompressed[7], - ]) as usize; - let mut files: Vec<(String, Vec)> = Vec::new(); - for i in 0..entry_count { - let base = footer_offset + i * 144; - if base + 144 > decompressed.len() { - break; - } - - let name_bytes = &decompressed[base..base + 128]; - let name: String = name_bytes - .chunks_exact(2) - .map(|c| u16::from_le_bytes([c[0], c[1]])) - .take_while(|&c| c != 0) - .filter_map(|c| char::from_u32(c as u32)) - .collect(); - - let length = u32::from_le_bytes([ - decompressed[base + 128], - decompressed[base + 129], - decompressed[base + 130], - decompressed[base + 131], - ]) as usize; - let start_offset = u32::from_le_bytes([ - decompressed[base + 132], - decompressed[base + 133], - decompressed[base + 134], - decompressed[base + 135], - ]) as usize; - if !name.is_empty() && length > 0 && start_offset + length <= decompressed.len() { - let data = decompressed[start_offset..start_offset + length].to_vec(); - files.push((name, data)); - } - } - - let out_dir = Path::new(&java_world_output); - fs::create_dir_all(out_dir).map_err(|e| format!("Failed to create output directory: {}", e))?; - fs::create_dir_all(out_dir.join("region")).map_err(|e| format!("Failed to create region directory: {}", e))?; - let mut chunks_written: usize = 0; - let mut errors: Vec = Vec::new(); - let mut region_writers: HashMap = HashMap::new(); - for (name, data) in &files { - if name == "level.dat" { - let lce_root = nbt::read_nbt(data).map_err(|e| format!("Failed to parse level.dat: {}", e))?; - let java_level_bytes = convert_lce_to_java(&lce_root, None, None, None, None); - fs::write(out_dir.join("level.dat"), &java_level_bytes).map_err(|e| format!("Failed to write level.dat: {}", e))?; - continue; - } - - if name.ends_with(".mcr") || name.ends_with(".mca") { - let mut reader = region::JavaRegionReader::open_from_bytes(data); - let parts: Vec<&str> = name.split('.').collect(); - let region_x: i32 = if parts.len() >= 4 { parts[1].parse().unwrap_or(0) } else { 0 }; - let region_z: i32 = if parts.len() >= 4 { parts[2].parse().unwrap_or(0) } else { 0 }; - for local_z in 0..32 { - for local_x in 0..32 { - let index = (local_x & 31) + (local_z & 31) * 32; - if reader.offsets[index as usize] == 0 { - continue; - } - - match reader.read_chunk(local_x, local_z) { - Ok(Some(lce_chunk_data)) => { - if let Some(legacy_nbt) = payload::try_decode_to_legacy_nbt(&lce_chunk_data) { - let root = nbt::read_nbt(&legacy_nbt).unwrap_or_default(); - let source_level = root.compound("Level").unwrap_or(&root); - let cx = region_x * 32 + local_x; - let cz = region_z * 32 + local_z; - let modern_root = build_modern_anvil_level(source_level, cx, cz); - let modern_nbt = nbt::write_nbt(&modern_root); - let out_region_x = cx >> 5; - let out_region_z = cz >> 5; - let out_local_x = cx & 31; - let out_local_z = cz & 31; - let section_region = format!("r.{}.{}.mca", out_region_x, out_region_z); - let region_path = out_dir.join("region").join(§ion_region); - let region_path_str = region_path.to_string_lossy().to_string(); - let writer = region_writers.entry(section_region.clone()).or_insert_with(|| { - JavaRegionFileWriter::load_from_file(®ion_path_str) - }); - writer.write_chunk(out_local_x, out_local_z, &modern_nbt); - chunks_written += 1; - } - } - Ok(None) => {} - Err(e) => { - errors.push(format!("{}/{}: {}", name, local_x * 32 + local_z, e)); - } - } - } - } - continue; - } - } - - for (region_name, writer) in &mut region_writers { - if let Err(e) = writer.save() { - errors.push(format!("Failed to save region {}: {}", region_name, e)); - } - } - - let mut msg = format!( - "Conversion complete!\nChunks: {}\nFiles: {}", - chunks_written, files.len() - ); - if !errors.is_empty() { - msg.push_str(&format!("\nErrors: {}", errors.len())); - for err in errors.iter().take(5) { - msg.push_str(&format!("\n {}", err)); - } - } - eprintln!("{}", msg); - Ok(msg) -} diff --git a/src-tauri/src/commands/java2lce/nbt.rs b/src-tauri/src/commands/java2lce/nbt.rs deleted file mode 100644 index 2db4003..0000000 --- a/src-tauri/src/commands/java2lce/nbt.rs +++ /dev/null @@ -1,504 +0,0 @@ -use std::io::{Read, Write}; -use flate2::read::GzDecoder; -use flate2::write::GzEncoder; -use flate2::Compression; -#[derive(Debug, Clone, PartialEq)] -pub enum NbtValue { - Byte(i8), - Short(i16), - Int(i32), - Long(i64), - Float(f32), - Double(f64), - ByteArray(Vec), - String(String), - List(Vec), - Compound(NbtCompound), - IntArray(Vec), - LongArray(Vec), -} - -#[derive(Debug, Clone, Default, PartialEq)] -pub struct NbtCompound { - pub name: String, - pub tags: Vec<(String, NbtValue)>, //neo: if you came here asking about this, dont. please. dont ask why im storing a tuple in a vec. or why im manually resizing a vec. -} - -impl NbtCompound { - pub fn new(name: &str) -> Self { - Self { - name: name.to_string(), - tags: Vec::new(), - } - } - - pub fn insert(&mut self, name: &str, value: NbtValue) { - self.tags.retain(|(n, _)| n != name); - self.tags.push((name.to_string(), value)); - } - - pub fn get(&self, name: &str) -> Option<&NbtValue> { - self.tags.iter().find(|(n, _)| n == name).map(|(_, v)| v) - } - - pub fn get_mut(&mut self, name: &str) -> Option<&mut NbtValue> { - self.tags.iter_mut().find(|(n, _)| n == name).map(|(_, v)| v) - } - - pub fn contains(&self, name: &str) -> bool { - self.tags.iter().any(|(n, _)| n == name) - } - - pub fn remove(&mut self, name: &str) { - self.tags.retain(|(n, _)| n != name); - } - - pub fn compound(&self, name: &str) -> Option<&NbtCompound> { - self.get(name).and_then(|v| match v { - NbtValue::Compound(c) => Some(c), - _ => None, - }) - } - /* - //neo: unused - pub fn compound_mut(&mut self, name: &str) -> Option<&mut NbtCompound> { - self.get_mut(name).and_then(|v| match v { - NbtValue::Compound(c) => Some(c), - _ => None, - }) - } -*/ - pub fn byte(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Byte(b) => Some(*b), - _ => None, - }) - } - - pub fn short(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Short(s) => Some(*s), - _ => None, - }) - } - - pub fn int(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Int(i) => Some(*i), - _ => None, - }) - } - - pub fn long(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Long(l) => Some(*l), - _ => None, - }) - } - /* - //neo: unused - pub fn float(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Float(f) => Some(*f), - _ => None, - }) - } - - pub fn double(&self, name: &str) -> Option { - self.get(name).and_then(|v| match v { - NbtValue::Double(d) => Some(*d), - _ => None, - }) - } -*/ - - pub fn string(&self, name: &str) -> Option<&str> { - self.get(name).and_then(|v| match v { - NbtValue::String(s) => Some(s.as_str()), - _ => None, - }) - } - - pub fn byte_array(&self, name: &str) -> Option<&[u8]> { - self.get(name).and_then(|v| match v { - NbtValue::ByteArray(b) => Some(b.as_slice()), - _ => None, - }) - } - - pub fn int_array(&self, name: &str) -> Option<&[i32]> { - self.get(name).and_then(|v| match v { - NbtValue::IntArray(a) => Some(a.as_slice()), - _ => None, - }) - } - - pub fn long_array(&self, name: &str) -> Option<&[i64]> { - self.get(name).and_then(|v| match v { - NbtValue::LongArray(a) => Some(a.as_slice()), - _ => None, - }) - } - - pub fn list(&self, name: &str) -> Option<&[NbtValue]> { - self.get(name).and_then(|v| match v { - NbtValue::List(l) => Some(l.as_slice()), - _ => None, - }) - } - /* - //neo: unused - pub fn list_compounds(&self, name: &str) -> Vec<&NbtCompound> { - self.list(name) - .unwrap_or(&[]) - .iter() - .filter_map(|v| match v { - NbtValue::Compound(c) => Some(c), - _ => None, - }) - .collect() - }*/ -} - -fn tag_type_id(v: &NbtValue) -> u8 { - match v { - NbtValue::Byte(_) => 1, - NbtValue::Short(_) => 2, - NbtValue::Int(_) => 3, - NbtValue::Long(_) => 4, - NbtValue::Float(_) => 5, - NbtValue::Double(_) => 6, - NbtValue::ByteArray(_) => 7, - NbtValue::String(_) => 8, - NbtValue::List(_) => 9, - NbtValue::Compound(_) => 10, - NbtValue::IntArray(_) => 11, - NbtValue::LongArray(_) => 12, - } -} - -fn read_be_i16(data: &[u8], off: usize) -> i16 { - i16::from_be_bytes([data[off], data[off + 1]]) -} - -fn read_be_i32(data: &[u8], off: usize) -> i32 { - i32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]) -} - -fn read_be_i64(data: &[u8], off: usize) -> i64 { - i64::from_be_bytes([ - data[off], - data[off + 1], - data[off + 2], - data[off + 3], - data[off + 4], - data[off + 5], - data[off + 6], - data[off + 7], - ]) -} - -fn read_be_f32(data: &[u8], off: usize) -> f32 { - f32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]) -} - -fn read_be_f64(data: &[u8], off: usize) -> f64 { - f64::from_be_bytes([ - data[off], - data[off + 1], - data[off + 2], - data[off + 3], - data[off + 4], - data[off + 5], - data[off + 6], - data[off + 7], - ]) -} - -fn read_string(data: &[u8], off: usize) -> Result<(String, usize), String> { - let len = read_be_i16(data, off) as usize; - let start = off + 2; - if start + len > data.len() { - return Err("string extends past end of data".into()); - } - let s = String::from_utf8_lossy(&data[start..start + len]).to_string(); - Ok((s, start + len)) -} - -pub fn read_nbt(data: &[u8]) -> Result { - if data.is_empty() { - return Err("empty NBT data".into()); - } - let mut pos = 0; - let tag_type = data[pos]; - pos += 1; - if tag_type != 10 { - return Err(format!("root tag is not compound (type={})", tag_type)); - } - let (name, new_pos) = read_string(data, pos)?; - pos = new_pos; - let (compound, _new_pos) = read_compound_payload(data, pos)?; - let mut result = compound; - result.name = name; - Ok(result) -} - -fn read_compound_payload(data: &[u8], mut pos: usize) -> Result<(NbtCompound, usize), String> { - let mut compound = NbtCompound::default(); - loop { - if pos >= data.len() { - return Err("unexpected end in compound".into()); - } - let tag_type = data[pos]; - pos += 1; - if tag_type == 0 { - break; - } - let (name, new_pos) = read_string(data, pos)?; - pos = new_pos; - let (value, new_pos) = read_value(data, pos, tag_type)?; - pos = new_pos; - compound.tags.push((name, value)); - } - Ok((compound, pos)) -} - -fn read_value(data: &[u8], pos: usize, tag_type: u8) -> Result<(NbtValue, usize), String> { - match tag_type { - 1 => Ok((NbtValue::Byte(data[pos] as i8), pos + 1)), - 2 => Ok((NbtValue::Short(read_be_i16(data, pos)), pos + 2)), - 3 => Ok((NbtValue::Int(read_be_i32(data, pos)), pos + 4)), - 4 => Ok((NbtValue::Long(read_be_i64(data, pos)), pos + 8)), - 5 => Ok((NbtValue::Float(read_be_f32(data, pos)), pos + 4)), - 6 => Ok((NbtValue::Double(read_be_f64(data, pos)), pos + 8)), - 7 => { - let len = read_be_i32(data, pos) as usize; - let start = pos + 4; - if start + len > data.len() { - return Err("byte array extends past end".into()); - } - Ok((NbtValue::ByteArray(data[start..start + len].to_vec()), start + len)) - } - 8 => { - let (s, new_pos) = read_string(data, pos)?; - Ok((NbtValue::String(s), new_pos)) - } - 9 => { - let elem_type = data[pos]; - let count = read_be_i32(data, pos + 1) as usize; - let mut list_pos = pos + 5; - let mut list = Vec::with_capacity(count); - for _ in 0..count { - let (val, new_pos) = read_value(data, list_pos, elem_type)?; - list_pos = new_pos; - list.push(val); - } - Ok((NbtValue::List(list), list_pos)) - } - 10 => { - let (compound, new_pos) = read_compound_payload(data, pos)?; - Ok((NbtValue::Compound(compound), new_pos)) - } - 11 => { - let len = read_be_i32(data, pos) as usize; - let start = pos + 4; - let mut arr = Vec::with_capacity(len); - for i in 0..len { - let off = start + i * 4; - if off + 4 > data.len() { - return Err("int array extends past end".into()); - } - arr.push(read_be_i32(data, off)); - } - Ok((NbtValue::IntArray(arr), start + len * 4)) - } - 12 => { - let len = read_be_i32(data, pos) as usize; - let start = pos + 4; - let mut arr = Vec::with_capacity(len); - for i in 0..len { - let off = start + i * 8; - if off + 8 > data.len() { - return Err("long array extends past end".into()); - } - arr.push(read_be_i64(data, off)); - } - Ok((NbtValue::LongArray(arr), start + len * 8)) - } - _ => Err(format!("unknown NBT tag type: {}", tag_type)), - } -} - -pub fn write_nbt(compound: &NbtCompound) -> Vec { - let mut out = Vec::new(); - out.push(10); - write_string(&mut out, &compound.name); - write_compound_payload(&mut out, compound); - out.push(0); - out -} - -fn write_string(out: &mut Vec, s: &str) { - let bytes = s.as_bytes(); - let len = (bytes.len() as i16).to_be_bytes(); - out.extend_from_slice(&len); - out.extend_from_slice(bytes); -} - -fn write_compound_payload(out: &mut Vec, compound: &NbtCompound) { - for (name, value) in &compound.tags { - out.push(tag_type_id(value)); - write_string(out, name); - write_value(out, value); - } -} - -fn write_value(out: &mut Vec, value: &NbtValue) { - match value { - NbtValue::Byte(b) => out.push(*b as u8), - NbtValue::Short(s) => out.extend_from_slice(&s.to_be_bytes()), - NbtValue::Int(i) => out.extend_from_slice(&i.to_be_bytes()), - NbtValue::Long(l) => out.extend_from_slice(&l.to_be_bytes()), - NbtValue::Float(f) => out.extend_from_slice(&f.to_be_bytes()), - NbtValue::Double(d) => out.extend_from_slice(&d.to_be_bytes()), - NbtValue::ByteArray(arr) => { - out.extend_from_slice(&(arr.len() as i32).to_be_bytes()); - out.extend_from_slice(arr); - } - NbtValue::String(s) => write_string(out, s), - NbtValue::List(list) => { - let elem_type = list.first().map(|v| tag_type_id(v)).unwrap_or(0); - out.push(elem_type); - out.extend_from_slice(&(list.len() as i32).to_be_bytes()); - for item in list { - write_value(out, item); - } - } - NbtValue::Compound(c) => { - write_compound_payload(out, c); - out.push(0); - } - NbtValue::IntArray(arr) => { - out.extend_from_slice(&(arr.len() as i32).to_be_bytes()); - for i in arr { - out.extend_from_slice(&i.to_be_bytes()); - } - } - NbtValue::LongArray(arr) => { - out.extend_from_slice(&(arr.len() as i32).to_be_bytes()); - for l in arr { - out.extend_from_slice(&l.to_be_bytes()); - } - } - } -} - -pub fn read_gzip_nbt(data: &[u8]) -> Result { - let mut decoder = GzDecoder::new(data); - let mut buf = Vec::new(); - decoder - .read_to_end(&mut buf) - .map_err(|e| format!("gzip decompress failed: {}", e))?; - read_nbt(&buf) -} - -pub fn write_gzip_nbt(compound: &NbtCompound) -> Vec { - let raw = write_nbt(compound); - let mut encoder = GzEncoder::new(Vec::new(), Compression::best()); - encoder.write_all(&raw).unwrap(); - encoder.finish().unwrap() -} - -/* -//neo: unused -pub fn read_zlib_nbt(data: &[u8]) -> Result { - use flate2::read::ZlibDecoder; - let mut decoder = ZlibDecoder::new(data); - let mut buf = Vec::new(); - decoder - .read_to_end(&mut buf) - .map_err(|e| format!("zlib decompress failed: {}", e))?; - read_nbt(&buf) -} - -pub fn write_zlib_nbt(compound: &NbtCompound) -> Vec { - use flate2::write::ZlibEncoder; - let raw = write_nbt(compound); - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best()); - encoder.write_all(&raw).unwrap(); - encoder.finish().unwrap() -} - -pub fn get_byte_array_or(compound: &NbtCompound, name: &str, default_len: usize) -> Vec { - compound - .byte_array(name) - .map(|b| { - let mut v = b.to_vec(); - if v.len() < default_len { - v.resize(default_len, 0); - } - v - }) - .unwrap_or_else(|| vec![0u8; default_len]) -} - -pub fn get_int_array_or(compound: &NbtCompound, name: &str, default_len: usize) -> Vec { - compound - .int_array(name) - .map(|a| { - let mut v = a.to_vec(); - if v.len() < default_len { - v.resize(default_len, 0); - } - v - }) - .unwrap_or_else(|| vec![0i32; default_len]) -} - -pub fn get_long_array_or(compound: &NbtCompound, name: &str, default_len: usize) -> Vec { - compound - .long_array(name) - .map(|a| { - let mut v = a.to_vec(); - if v.len() < default_len { - v.resize(default_len, 0); - } - v - }) - .unwrap_or_else(|| vec![0i64; default_len]) -} -*/ -pub fn get_nibble(data: &[u8], index: usize) -> u8 { - let byte_index = index >> 1; - if byte_index >= data.len() { - return 0; - } - let b = data[byte_index]; - if index & 1 == 0 { - b & 0x0F - } else { - (b >> 4) & 0x0F - } -} - -pub fn set_nibble(data: &mut [u8], index: usize, value: u8) { - let byte_index = index >> 1; - if byte_index >= data.len() { - return; - } - let val = value & 0x0F; - if index & 1 == 0 { - data[byte_index] = (data[byte_index] & 0xF0) | val; - } else { - data[byte_index] = (data[byte_index] & 0x0F) | (val << 4); - } -} -/* -//neo: unused -pub fn clone_or_empty_list(compound: &NbtCompound, name: &str) -> Vec { - compound - .list(name) - .map(|l| l.to_vec()) - .unwrap_or_default() -} -*/ diff --git a/src-tauri/src/commands/java2lce/payload.rs b/src-tauri/src/commands/java2lce/payload.rs deleted file mode 100644 index 0bff1d1..0000000 --- a/src-tauri/src/commands/java2lce/payload.rs +++ /dev/null @@ -1,696 +0,0 @@ -use super::nbt; -const SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE: i16 = 8; -const SAVE_FILE_VERSION_CHUNK_INHABITED_TIME: i16 = 9; -const COMPRESSED_CHUNK_SECTION_HEIGHT: usize = 128; -const BLOCKS_PER_SECTION: usize = COMPRESSED_CHUNK_SECTION_HEIGHT * 16 * 16; -const NIBBLES_PER_SECTION: usize = BLOCKS_PER_SECTION / 2; -const FULL_CHUNK_BLOCKS: usize = 256 * 16 * 16; -const FULL_CHUNK_NIBBLES: usize = FULL_CHUNK_BLOCKS / 2; -const INDEX_TYPE_MASK: u16 = 0x0003; -const INDEX_TYPE_1BIT: u16 = 0x0000; -const INDEX_TYPE_2BIT: u16 = 0x0001; -const INDEX_TYPE_4BIT: u16 = 0x0002; -const INDEX_TYPE_0_OR_8BIT: u16 = 0x0003; -const INDEX_TYPE_0BIT_FLAG: u16 = 0x0004; -const SPARSE_ALL_ZERO_INDEX: u8 = 128; -const SPARSE_ALL_FIFTEEN_INDEX: u8 = 129; -fn read_be_i16(data: &[u8], off: usize) -> i16 { - i16::from_be_bytes([data[off], data[off + 1]]) -} - -fn read_be_i32(data: &[u8], off: usize) -> i32 { - i32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]) -} - -fn read_be_i64(data: &[u8], off: usize) -> i64 { - i64::from_be_bytes([ - data[off], data[off + 1], data[off + 2], data[off + 3], data[off + 4], data[off + 5], - data[off + 6], data[off + 7], - ]) -} -/* -//neo: unused -fn write_be_i16(out: &mut Vec, v: i16) { - out.extend_from_slice(&v.to_be_bytes()); -} - -fn write_be_i32(out: &mut Vec, v: i32) { - out.extend_from_slice(&v.to_be_bytes()); -} - -fn write_be_i64(out: &mut Vec, v: i64) { - out.extend_from_slice(&v.to_be_bytes()); -}*/ - -fn get_compressed_tile_index(block: usize, tile: usize) -> usize { - let mut index = ((block & 0x180) << 6) | ((block & 0x060) << 4) | ((block & 0x01F) << 2); - index |= ((tile & 0x30) << 7) | ((tile & 0x0C) << 5) | (tile & 0x03); - index -} -/* -//neo: unused -fn get_nibble_value(nibble_data: &[u8], xz: usize, y: usize) -> u8 { - let pos = (xz << 7) | y; - let slot = pos >> 1; - let part = pos & 1; - if slot >= nibble_data.len() { - return 0; - } - let b = nibble_data[slot]; - if part == 0 { - b & 0x0F - } else { - (b >> 4) & 0x0F - } -}*/ - -fn set_nibble_value(nibble_data: &mut [u8], xz: usize, y: usize, value: u8) { - let pos = (xz << 7) | y; - let slot = pos >> 1; - let part = pos & 1; - if slot >= nibble_data.len() { - return; - } - let val = value & 0x0F; - if part == 0 { - nibble_data[slot] = (nibble_data[slot] & 0xF0) | val; - } else { - nibble_data[slot] = (nibble_data[slot] & 0x0F) | (val << 4); - } -} - -/* -//neo: unused -fn ensure_length(input: &[u8], expected_len: usize) -> Vec { - if input.len() == expected_len { - return input.to_vec(); - } - let mut v = vec![0u8; expected_len]; - let copy_len = input.len().min(expected_len); - v[..copy_len].copy_from_slice(&input[..copy_len]); - v -} - -fn extract_lower_block_section(full_blocks: &[u8]) -> Vec { - if full_blocks.len() == BLOCKS_PER_SECTION { - return full_blocks.to_vec(); - } - let mut lower = vec![0u8; BLOCKS_PER_SECTION]; - for xz in 0..256 { - let src_start = xz * 256; - let dst_start = xz * COMPRESSED_CHUNK_SECTION_HEIGHT; - let copy_len = COMPRESSED_CHUNK_SECTION_HEIGHT.min(full_blocks.len() - src_start.min(full_blocks.len())); - if src_start + copy_len <= full_blocks.len() && dst_start + copy_len <= BLOCKS_PER_SECTION { - lower[dst_start..dst_start + copy_len] - .copy_from_slice(&full_blocks[src_start..src_start + copy_len]); - } - } - lower -} - -fn extract_upper_block_section(full_blocks: &[u8]) -> Vec { - if full_blocks.len() < FULL_CHUNK_BLOCKS { - return vec![0u8; BLOCKS_PER_SECTION]; - } - let mut upper = vec![0u8; BLOCKS_PER_SECTION]; - for xz in 0..256 { - let src_start = xz * 256 + COMPRESSED_CHUNK_SECTION_HEIGHT; - let dst_start = xz * COMPRESSED_CHUNK_SECTION_HEIGHT; - upper[dst_start..dst_start + COMPRESSED_CHUNK_SECTION_HEIGHT].copy_from_slice(&full_blocks[src_start..src_start + COMPRESSED_CHUNK_SECTION_HEIGHT]); - } - upper -}*/ - -fn extract_lower_nibble_section(full_nibbles: &[u8]) -> Vec { - let nibble_height = COMPRESSED_CHUNK_SECTION_HEIGHT / 2; - if full_nibbles.len() == NIBBLES_PER_SECTION { - return full_nibbles.to_vec(); - } - let mut lower = vec![0u8; NIBBLES_PER_SECTION]; - for xz in 0..256 { - let src_start = xz * nibble_height * 2; - let dst_start = xz * nibble_height; - let copy_len = nibble_height.min( - full_nibbles.len().saturating_sub(src_start), - ); - if copy_len > 0 { - lower[dst_start..dst_start + copy_len].copy_from_slice(&full_nibbles[src_start..src_start + copy_len]); - } - } - lower -} -/* -//neo: unused -fn extract_upper_nibble_section(full_nibbles: &[u8]) -> Vec { - let nibble_height = COMPRESSED_CHUNK_SECTION_HEIGHT / 2; - if full_nibbles.len() < FULL_CHUNK_NIBBLES { - return vec![0u8; NIBBLES_PER_SECTION]; - } - let mut upper = vec![0u8; NIBBLES_PER_SECTION]; - for xz in 0..256 { - let src_start = xz * nibble_height * 2 + nibble_height; - let dst_start = xz * nibble_height; - upper[dst_start..dst_start + nibble_height] - .copy_from_slice(&full_nibbles[src_start..src_start + nibble_height]); - } - upper -}*/ - -fn combine_block_sections(lower: &[u8], upper: &[u8]) -> Vec { - if lower.len() == FULL_CHUNK_BLOCKS { - return lower.to_vec(); - } - let mut combined = vec![0u8; FULL_CHUNK_BLOCKS]; - for xz in 0..256 { - let lower_start = xz * COMPRESSED_CHUNK_SECTION_HEIGHT; - let out_start = xz * 256; - let copy_len = COMPRESSED_CHUNK_SECTION_HEIGHT.min(lower.len().saturating_sub(lower_start)); - if copy_len > 0 { - combined[out_start..out_start + copy_len].copy_from_slice(&lower[lower_start..lower_start + copy_len]); - } - let upper_start = xz * COMPRESSED_CHUNK_SECTION_HEIGHT; - let out_upper = out_start + COMPRESSED_CHUNK_SECTION_HEIGHT; - let copy_len2 = COMPRESSED_CHUNK_SECTION_HEIGHT.min(upper.len().saturating_sub(upper_start)); - if copy_len2 > 0 { - combined[out_upper..out_upper + copy_len2] - .copy_from_slice(&upper[upper_start..upper_start + copy_len2]); - } - } - combined -} - -fn combine_nibble_sections(lower: &[u8], upper: &[u8]) -> Vec { - let nibble_height = COMPRESSED_CHUNK_SECTION_HEIGHT / 2; - if lower.len() == FULL_CHUNK_NIBBLES { - return lower.to_vec(); - } - let mut combined = vec![0u8; FULL_CHUNK_NIBBLES]; - for xz in 0..256 { - let lower_start = xz * nibble_height; - let out_start = xz * nibble_height * 2; - let copy_len = nibble_height.min(lower.len().saturating_sub(lower_start)); - if copy_len > 0 { - combined[out_start..out_start + copy_len] - .copy_from_slice(&lower[lower_start..lower_start + copy_len]); - } - let upper_start = xz * nibble_height; - let out_upper = out_start + nibble_height; - let copy_len2 = nibble_height.min(upper.len().saturating_sub(upper_start)); - if copy_len2 > 0 { - combined[out_upper..out_upper + copy_len2] - .copy_from_slice(&upper[upper_start..upper_start + copy_len2]); - } - } - combined -} - -pub fn encode_legacy_nbt(level: &nbt::NbtCompound) -> Vec { - let mut root = nbt::NbtCompound::new(""); - root.insert("Level", nbt::NbtValue::Compound(level.clone())); - nbt::write_nbt(&root) -} - -/* -//neo: unused -fn write_compressed_tile_storage(out: &mut Vec, blocks: &[u8]) { - let normalized = ensure_length(blocks, BLOCKS_PER_SECTION); - let mut blob = vec![0u8; 1024 + BLOCKS_PER_SECTION]; - let mut data_offset: usize = 0; - for block in 0..512 { - let index = (INDEX_TYPE_0_OR_8BIT | ((data_offset as u16) << 1)) as u16; - blob[block * 2..block * 2 + 2].copy_from_slice(&index.to_le_bytes()); - for tile in 0..64 { - blob[1024 + data_offset + tile] = normalized[get_compressed_tile_index(block, tile)]; - } - data_offset += 64; - } - - write_be_i32(out, blob.len() as i32); - out.extend_from_slice(&blob); -} - -fn write_empty_compressed_tile_storage(out: &mut Vec) { - let mut blob = vec![0u8; 1024]; - for block in 0..512 { - let index = (INDEX_TYPE_0_OR_8BIT | INDEX_TYPE_0BIT_FLAG) as u16; - blob[block * 2..block * 2 + 2].copy_from_slice(&index.to_le_bytes()); - } - write_be_i32(out, blob.len() as i32); - out.extend_from_slice(&blob); -} - -fn write_sparse_nibble_storage(out: &mut Vec, nibble_data: &[u8], supports_all_fifteen: bool) { - let normalized = ensure_length(nibble_data, NIBBLES_PER_SECTION); - let mut plane_indices = [0u8; 128]; - let mut planes: Vec> = Vec::new(); - for y in 0..128 { - let mut all_zero = true; - let mut all_fifteen = supports_all_fifteen; - let mut plane = vec![0u8; 128]; - let mut plane_cursor = 0; - for xz in 0..128 { - let first = get_nibble_value(&normalized, xz * 2, y); - let second = get_nibble_value(&normalized, xz * 2 + 1, y); - - if first != 0 || second != 0 { - all_zero = false; - } - if supports_all_fifteen && (first != 15 || second != 15) { - all_fifteen = false; - } - - plane[plane_cursor] = first | (second << 4); - plane_cursor += 1; - } - - if all_zero { - plane_indices[y] = SPARSE_ALL_ZERO_INDEX; - continue; - } - if supports_all_fifteen && all_fifteen { - plane_indices[y] = SPARSE_ALL_FIFTEEN_INDEX; - continue; - } - - plane_indices[y] = planes.len() as u8; - planes.push(plane); - } - - write_be_i32(out, planes.len() as i32); - out.extend_from_slice(&plane_indices); - for plane in &planes { - out.extend_from_slice(plane); - } -} - -fn write_empty_sparse_nibble_storage(out: &mut Vec, supports_all_fifteen: bool, fill_with_fifteen: bool) { - write_be_i32(out, 0); - let fill = if supports_all_fifteen && fill_with_fifteen { - SPARSE_ALL_FIFTEEN_INDEX - } else { - SPARSE_ALL_ZERO_INDEX - }; - let plane_indices = [fill; 128]; - out.extend_from_slice(&plane_indices); -} - -pub fn encode_compressed_storage(level: &nbt::NbtCompound) -> Vec { - let blocks = level.byte_array("Blocks").unwrap_or(&[]); - let data = level.byte_array("Data").unwrap_or(&[]); - let sky_light_raw = level.byte_array("SkyLight").unwrap_or(&[]); - let block_light_raw = level.byte_array("BlockLight").unwrap_or(&[]); - let height_map = level.byte_array("HeightMap").unwrap_or(&[]); - let biomes = level.byte_array("Biomes").unwrap_or(&[]); - let default_sky = vec![0xFF; NIBBLES_PER_SECTION]; - let default_light = vec![0u8; NIBBLES_PER_SECTION]; - let sky_light = if sky_light_raw.is_empty() { default_sky.as_slice() } else { sky_light_raw }; - let block_light = if block_light_raw.is_empty() { default_light.as_slice() } else { block_light_raw }; - let mut out = Vec::new(); - write_be_i16(&mut out, SAVE_FILE_VERSION_CHUNK_INHABITED_TIME); - write_be_i32(&mut out, level.int("xPos").unwrap_or(0)); - write_be_i32(&mut out, level.int("zPos").unwrap_or(0)); - write_be_i64(&mut out, level.long("LastUpdate").unwrap_or(0)); - write_be_i64(&mut out, level.long("InhabitedTime").unwrap_or(0)); - write_compressed_tile_storage(&mut out, &extract_lower_block_section(blocks)); - write_compressed_tile_storage(&mut out, &extract_upper_block_section(blocks)); - write_sparse_nibble_storage(&mut out, &extract_lower_nibble_section(data), false); - write_sparse_nibble_storage(&mut out, &extract_upper_nibble_section(data), false); - write_sparse_nibble_storage(&mut out, &extract_lower_nibble_section(sky_light), true); - write_sparse_nibble_storage(&mut out, &extract_upper_nibble_section(sky_light), true); - write_sparse_nibble_storage(&mut out, &extract_lower_nibble_section(block_light), true); - write_sparse_nibble_storage(&mut out, &extract_upper_nibble_section(block_light), true); - let hm = ensure_length(height_map, 256); - out.extend_from_slice(&hm[..256]); - write_be_i16(&mut out, level.short("TerrainPopulatedFlags").unwrap_or(0)); - let bio = ensure_length(biomes, 256); - out.extend_from_slice(&bio[..256]); - let dynamic_root = nbt::NbtCompound::new(""); - let dynamic_bytes = nbt::write_nbt(&dynamic_root); - out.extend_from_slice(&dynamic_bytes); - out -}*/ - -fn is_compressed_chunk_storage(data: &[u8]) -> bool { - if data.len() < 2 + 4 + 4 + 8 { - return false; - } - let version = read_be_i16(data, 0); - version == SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE || version == SAVE_FILE_VERSION_CHUNK_INHABITED_TIME -} -/* -//neo: unused -pub fn try_read_chunk_coordinates( - data: &[u8], -) -> Option<(i32, i32, bool)> { - if let Some((cx, cz, wrapped)) = try_read_legacy_level_coords(data) { - return Some((cx, cz, wrapped)); - } - - if is_compressed_chunk_storage(data) { - let cx = read_be_i32(data, 2); - let cz = read_be_i32(data, 6); - return Some((cx, cz, false)); - } - - None -} - -fn try_read_legacy_level_coords(data: &[u8]) -> Option<(i32, i32, bool)> { - if data.is_empty() || data[0] != 10 { - return None; - } - let compound = nbt::read_nbt(data).ok()?; - let (level, has_wrapper) = if let Some(nbt::NbtValue::Compound(c)) = compound.get("Level") { - (c, true) - } else { - (&compound, false) - }; - let cx = level.int("xPos")?; - let cz = level.int("zPos")?; - Some((cx, cz, has_wrapper)) -} - -pub fn force_chunk_coordinates(data: &[u8], expected_x: i32, expected_z: i32) -> Vec { - if data.is_empty() { - return Vec::new(); - } - - if let Ok((mut level, _)) = read_legacy_level(data) { - level.insert("xPos", nbt::NbtValue::Int(expected_x)); - level.insert("zPos", nbt::NbtValue::Int(expected_z)); - return encode_legacy_nbt(&level); - } - - if is_compressed_chunk_storage(data) { - let mut patched = data.to_vec(); - patched[2..6].copy_from_slice(&expected_x.to_be_bytes()); - patched[6..10].copy_from_slice(&expected_z.to_be_bytes()); - return patched; - } - - Vec::new() -} -*/ -fn read_compressed_tile_storage(data: &[u8], offset: &mut usize) -> Result, String> { - let allocated_size = read_be_i32(data, *offset) as usize; - *offset += 4; - if allocated_size < 1024 || *offset + allocated_size > data.len() { - return Err("Invalid CompressedTileStorage payload.".into()); - } - - let blob = &data[*offset..*offset + allocated_size]; - *offset += allocated_size; - let data_region = &blob[1024..]; - let mut blocks = vec![0u8; BLOCKS_PER_SECTION]; - for block in 0..512 { - let block_index = u16::from_le_bytes([blob[block * 2], blob[block * 2 + 1]]); - let index_type = block_index & INDEX_TYPE_MASK; - if index_type == INDEX_TYPE_0_OR_8BIT { - if (block_index & INDEX_TYPE_0BIT_FLAG) != 0 { - let value = ((block_index >> 8) & 0xFF) as u8; - for tile in 0..64 { - blocks[get_compressed_tile_index(block, tile)] = value; - } - } else { - let data_offset = ((block_index >> 1) & 0x7FFE) as usize; - if data_offset + 64 > data_region.len() { - return Err("Invalid 8-bit CompressedTileStorage offset.".into()); - } - for tile in 0..64 { - blocks[get_compressed_tile_index(block, tile)] = data_region[data_offset + tile]; - } - } - continue; - } - - let bits_per_tile = match index_type { - INDEX_TYPE_1BIT => 1, - INDEX_TYPE_2BIT => 2, - INDEX_TYPE_4BIT => 4, - _ => return Err("Unsupported CompressedTileStorage index type.".into()), - }; - - let tile_type_count = 1usize << bits_per_tile; - let tile_type_mask = (tile_type_count - 1) as u8; - let index_shift = 3 - index_type as usize; - let index_mask_bits = (7 >> index_type) as usize; - let index_mask_bytes = (62 >> index_shift) as usize; - let packed_data_size = (8usize << index_type) as usize; - let data_offset_packed = ((block_index >> 1) & 0x7FFE) as usize; - if data_offset_packed + tile_type_count + packed_data_size > data_region.len() { - return Err("Invalid packed CompressedTileStorage offset.".into()); - } - - let tile_types = &data_region[data_offset_packed..data_offset_packed + tile_type_count]; - let packed = &data_region[data_offset_packed + tile_type_count..data_offset_packed + tile_type_count + packed_data_size]; - for tile in 0..64 { - let idx = (tile >> index_shift) & index_mask_bytes; - let bit = (tile & index_mask_bits) * bits_per_tile; - let palette_index = (packed[idx] >> bit) & tile_type_mask; - blocks[get_compressed_tile_index(block, tile)] = tile_types[palette_index as usize]; - } - } - - Ok(blocks) -} -/* -//neo: unused -fn skip_compressed_tile_storage(data: &[u8], offset: &mut usize) -> Result<(), String> { - let allocated_size = read_be_i32(data, *offset) as usize; - *offset += 4; - if *offset + allocated_size > data.len() { - return Err("Invalid CompressedTileStorage payload.".into()); - } - *offset += allocated_size; - Ok(()) -} -*/ - -fn read_sparse_nibble_storage(data: &[u8], offset: &mut usize, supports_all_fifteen: bool) -> Result, String> { - let count = read_be_i32(data, *offset) as usize; - *offset += 4; - let storage_bytes = 128 + count * 128; - if count > data.len() || *offset + storage_bytes > data.len() { - return Err("Invalid SparseStorage payload.".into()); - } - - let blob = &data[*offset..*offset + storage_bytes]; - *offset += storage_bytes; - let plane_indices = &blob[..128]; - let plane_data = &blob[128..]; - let mut nibble_data = vec![0u8; NIBBLES_PER_SECTION]; - for y in 0..128 { - let plane_index = plane_indices[y]; - if plane_index == SPARSE_ALL_ZERO_INDEX { - continue; - } - if supports_all_fifteen && plane_index == SPARSE_ALL_FIFTEEN_INDEX { - for xz in 0..256 { - set_nibble_value(&mut nibble_data, xz, y, 15); - } - continue; - } - - let plane_offset = plane_index as usize * 128; - if plane_offset + 128 > plane_data.len() { - return Err("Invalid sparse plane index.".into()); - } - - let plane = &plane_data[plane_offset..plane_offset + 128]; - for xz in 0..128 { - let packed = plane[xz]; - set_nibble_value(&mut nibble_data, xz * 2, y, packed & 0x0F); - set_nibble_value(&mut nibble_data, xz * 2 + 1, y, (packed >> 4) & 0x0F); - } - } - - Ok(nibble_data) -} -/* -//neo: unused -fn skip_sparse_nibble_storage(data: &[u8], offset: &mut usize) -> Result<(), String> { - let count = read_be_i32(data, *offset) as usize; - *offset += 4; - let storage_bytes = 128 + count * 128; - if count > data.len() || *offset + storage_bytes > data.len() { - return Err("Invalid SparseStorage payload.".into()); - } - *offset += storage_bytes; - Ok(()) -} -*/ -fn read_sized_bytes(data: &[u8], offset: &mut usize, length: usize) -> Vec { - let end = (*offset + length).min(data.len()); - let result = data[*offset..end].to_vec(); - *offset += length; - result -} - -fn read_legacy_level(data: &[u8]) -> Result<(nbt::NbtCompound, bool), String> { - if data.is_empty() || data[0] != 10 { - return Err("Not NBT compound".into()); - } - let file = nbt::read_nbt(data)?; - let has_level = file.get("Level").is_some(); - let level = if let Some(nbt::NbtValue::Compound(c)) = file.get("Level") { - let mut cloned = c.clone(); - cloned.name = "Level".to_string(); - cloned - } else { - let mut cloned = file.clone(); - cloned.name = "Level".to_string(); - cloned - }; - Ok((level, has_level)) -} - -pub fn try_decode_to_legacy_nbt(data: &[u8]) -> Option> { - if let Ok((mut level, _)) = read_legacy_level(data) { - level.name = "Level".to_string(); - return Some(encode_legacy_nbt(&level)); - } - - if !is_compressed_chunk_storage(data) { - return None; - } - - decode_compressed_chunk_to_legacy_root(data).ok().map(|root| nbt::write_nbt(&root)) -} - -fn decode_compressed_chunk_to_legacy_root(data: &[u8]) -> Result { - let mut offset = 0; - let version = read_be_i16(data, offset); - offset = 2; - if version != SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE - && version != SAVE_FILE_VERSION_CHUNK_INHABITED_TIME - { - return Err(format!("Unsupported compressed chunk version: {}", version)); - } - - let chunk_x = read_be_i32(data, offset); - offset += 4; - let chunk_z = read_be_i32(data, offset); - offset += 4; - let last_update = read_be_i64(data, offset); - offset += 8; - let inhabited_time = if version >= SAVE_FILE_VERSION_CHUNK_INHABITED_TIME { - let v = read_be_i64(data, offset); - offset += 8; - v - } else { - 0 - }; - - let lower_blocks = read_compressed_tile_storage(data, &mut offset)?; - let upper_blocks = read_compressed_tile_storage(data, &mut offset)?; - let lower_data = read_sparse_nibble_storage(data, &mut offset, false)?; - let upper_data = read_sparse_nibble_storage(data, &mut offset, false)?; - let lower_sky = read_sparse_nibble_storage(data, &mut offset, true)?; - let upper_sky = read_sparse_nibble_storage(data, &mut offset, true)?; - let lower_block_light = read_sparse_nibble_storage(data, &mut offset, true)?; - let upper_block_light = read_sparse_nibble_storage(data, &mut offset, true)?; - let height_map = read_sized_bytes(data, &mut offset, 256); - let terrain_populated_flags = read_be_i16(data, offset); - offset += 2; - let biomes = read_sized_bytes(data, &mut offset, 256); - let dynamic_root = if offset < data.len() { - nbt::read_nbt(&data[offset..]).unwrap_or_default() - } else { - nbt::NbtCompound::default() - }; - - let mut level = nbt::NbtCompound::new("Level"); - level.insert("xPos", nbt::NbtValue::Int(chunk_x)); - level.insert("zPos", nbt::NbtValue::Int(chunk_z)); - level.insert("LastUpdate", nbt::NbtValue::Long(last_update)); - level.insert("InhabitedTime", nbt::NbtValue::Long(inhabited_time)); - level.insert( - "Blocks", - nbt::NbtValue::ByteArray(combine_block_sections(&lower_blocks, &upper_blocks)), - ); - level.insert( - "Data", - nbt::NbtValue::ByteArray(combine_nibble_sections(&lower_data, &upper_data)), - ); - level.insert( - "SkyLight", - nbt::NbtValue::ByteArray(combine_nibble_sections(&lower_sky, &upper_sky)), - ); - level.insert( - "BlockLight", - nbt::NbtValue::ByteArray(combine_nibble_sections( - &lower_block_light, - &upper_block_light, - )), - ); - level.insert("HeightMap", nbt::NbtValue::ByteArray(height_map)); - level.insert( - "TerrainPopulatedFlags", - nbt::NbtValue::Short(terrain_populated_flags), - ); - level.insert("Biomes", nbt::NbtValue::ByteArray(biomes)); - let entities = dynamic_root - .list("Entities") - .map(|l| nbt::NbtValue::List(l.to_vec())) - .unwrap_or_else(|| nbt::NbtValue::List(Vec::new())); - level.insert("Entities", entities); - let tile_entities = dynamic_root - .list("TileEntities") - .map(|l| nbt::NbtValue::List(l.to_vec())) - .unwrap_or_else(|| nbt::NbtValue::List(Vec::new())); - level.insert("TileEntities", tile_entities); - if let Some(tile_ticks) = dynamic_root.get("TileTicks") { - level.insert("TileTicks", tile_ticks.clone()); - } - - let mut root = nbt::NbtCompound::new(""); - root.insert("Level", nbt::NbtValue::Compound(level)); - Ok(root) -} -/* -//neo: unused -pub fn try_get_compressed_chunk_nbt_offset(data: &[u8]) -> Option { - if !is_compressed_chunk_storage(data) { - return None; - } - - let mut offset = 0; - let version = read_be_i16(data, offset); - offset = 2; - if version != SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE - && version != SAVE_FILE_VERSION_CHUNK_INHABITED_TIME - { - return None; - } - - offset += 8; - if version >= SAVE_FILE_VERSION_CHUNK_INHABITED_TIME { - offset += 8; - } - - let r1 = skip_compressed_tile_storage(data, &mut offset); - if r1.is_err() { return None; } - let r2 = skip_compressed_tile_storage(data, &mut offset); - if r2.is_err() { return None; } - let r3 = skip_sparse_nibble_storage(data, &mut offset); - if r3.is_err() { return None; } - let r4 = skip_sparse_nibble_storage(data, &mut offset); - if r4.is_err() { return None; } - let r5 = skip_sparse_nibble_storage(data, &mut offset); - if r5.is_err() { return None; } - let r6 = skip_sparse_nibble_storage(data, &mut offset); - if r6.is_err() { return None; } - let r7 = skip_sparse_nibble_storage(data, &mut offset); - if r7.is_err() { return None; } - let r8 = skip_sparse_nibble_storage(data, &mut offset); - if r8.is_err() { return None; } - offset += 256; - offset += 2; - offset += 256; - if offset > data.len() { - return None; - } - - Some(offset) -} -*/ diff --git a/src-tauri/src/commands/java2lce/region.rs b/src-tauri/src/commands/java2lce/region.rs deleted file mode 100644 index f00df26..0000000 --- a/src-tauri/src/commands/java2lce/region.rs +++ /dev/null @@ -1,806 +0,0 @@ -use std::collections::HashMap; -use std::fs; -use std::io::{Read, Write}; -use std::path::Path; -use flate2::read::ZlibDecoder; -use flate2::write::ZlibEncoder; -use flate2::Compression; -use super::nbt::{self, NbtCompound, NbtValue}; -const SECTOR_BYTES: usize = 4096; -pub struct JavaWorldReader { - world_path: String, - region_readers: HashMap, -} - -pub struct JavaRegionReader { - pub data: Vec, - pub offsets: [u32; 1024], -} - -impl JavaWorldReader { - pub fn new(world_path: &str) -> Self { - Self { - world_path: world_path.to_string(), - region_readers: HashMap::new(), - } - } - - pub fn read_level_dat(&self) -> Result { - let path = Path::new(&self.world_path).join("level.dat"); - let data = fs::read(&path).map_err(|e| format!("Failed to read level.dat: {}", e))?; - nbt::read_gzip_nbt(&data) - } - - pub fn get_region_dir(&self, dimension: &str) -> String { - if dimension.is_empty() { - Path::new(&self.world_path) - .join("region") - .to_string_lossy() - .to_string() - } else { - Path::new(&self.world_path) - .join(dimension) - .join("region") - .to_string_lossy() - .to_string() - } - } - - pub fn get_region_files(&self, dimension: &str) -> Vec<(i32, i32, String)> { - let mut result = Vec::new(); - let dir = self.get_region_dir(dimension); - let dir_path = Path::new(&dir); - if !dir_path.is_dir() { - return result; - } - - if let Ok(entries) = fs::read_dir(dir_path) { - for entry in entries.flatten() { - let name = entry.file_name().to_string_lossy().to_string(); - let lower = name.to_lowercase(); - if lower.ends_with(".mcr") || lower.ends_with(".mca") { - let parts: Vec<&str> = name.split('.').collect(); - if parts.len() == 4 && parts[0] == "r" { - if let (Ok(rx), Ok(rz)) =(parts[1].parse::(), parts[2].parse::()) - { - result.push((rx, rz, entry.path().to_string_lossy().to_string())); - } - } - } - } - } - - result - } - /* - //neo: unused - pub fn is_anvil_world(&self) -> bool { - let region_dir = self.get_region_dir(""); - let dir_path = Path::new(®ion_dir); - if !dir_path.is_dir() { - return false; - } - if let Ok(entries) = fs::read_dir(dir_path) { - for entry in entries.flatten() { - let name = entry.file_name().to_string_lossy().to_string(); - if name.to_lowercase().ends_with(".mca") { - return true; - } - } - } - false - } -*/ - fn get_or_create_reader(&mut self, region_path: &str) -> Result<&JavaRegionReader, String> { - if !self.region_readers.contains_key(region_path) { - let reader = JavaRegionReader::open(region_path)?; - self.region_readers.insert(region_path.to_string(), reader); - } - Ok(self.region_readers.get(region_path).unwrap()) - } -/* - //neo: unused - pub fn has_chunk(&mut self, region_path: &str, local_x: i32, local_z: i32) -> bool { - let reader = match self.get_or_create_reader(region_path) { - Ok(r) => r, - Err(_) => return false, - }; - let index = (local_x & 31) + (local_z & 31) * 32; - reader.offsets[index as usize] != 0 - } -*/ - pub fn read_chunk_nbt( - &mut self, - region_path: &str, - local_x: i32, - local_z: i32, - ) -> Result, String> { - let reader = self.get_or_create_reader(region_path)?; - let index = (local_x & 31) + (local_z & 31) * 32; - let offset_entry = reader.offsets[index as usize]; - if offset_entry == 0 { - return Ok(None); - } - - let sector_offset = (offset_entry >> 8) as usize; - let chunk_pos = sector_offset * SECTOR_BYTES; - let data_len = reader.data.len(); - if chunk_pos + 5 > data_len { - return Ok(None); - } - - let length = u32::from_be_bytes([ - reader.data[chunk_pos], - reader.data[chunk_pos + 1], - reader.data[chunk_pos + 2], - reader.data[chunk_pos + 3], - ]) as usize; - let compression_type = reader.data[chunk_pos + 4]; - if length <= 1 { - return Ok(None); - } - - let compressed_length = length - 1; - if chunk_pos + 5 + compressed_length > data_len { - return Ok(None); - } - - let compressed_data = &reader.data[chunk_pos + 5..chunk_pos + 5 + compressed_length]; - let decompressed = match compression_type { - 1 => { - let mut decoder = flate2::read::GzDecoder::new(compressed_data); - let mut buf = Vec::new(); - decoder.read_to_end(&mut buf).map_err(|e| format!("gzip decompress failed: {}", e))?; - buf - } - 2 => { - let mut decoder = ZlibDecoder::new(compressed_data); - let mut buf = Vec::new(); - decoder - .read_to_end(&mut buf) - .map_err(|e| format!("zlib decompress failed: {}", e))?; - buf - } - _ => return Ok(None), - }; - - if decompressed.is_empty() { - return Ok(None); - } - - let compound = nbt::read_nbt(&decompressed)?; - Ok(Some(compound)) - } -} - -impl JavaRegionReader { - fn open(path: &str) -> Result { - let data = fs::read(path).map_err(|e| format!("Failed to read region file: {}", e))?; - let mut offsets = [0u32; 1024]; - for i in 0..1024 { - let off = i * 4; - if off + 4 > data.len() { - break; - } - offsets[i] = u32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]); - } - - Ok(Self { data, offsets }) - } - - pub fn open_from_bytes(data: &[u8]) -> Self { - let data = data.to_vec(); - let mut offsets = [0u32; 1024]; - for i in 0..1024 { - let off = i * 4; - if off + 4 > data.len() { - break; - } - offsets[i] = u32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]); - } - - Self { data, offsets } - } - - pub fn read_chunk( - &mut self, - local_x: i32, - local_z: i32, - ) -> Result>, String> { - let index = (local_x & 31) + (local_z & 31) * 32; - let offset_entry = self.offsets[index as usize]; - if offset_entry == 0 { - return Ok(None); - } - - let sector_offset = (offset_entry >> 8) as usize; - let chunk_pos = sector_offset * SECTOR_BYTES; - let data_len = self.data.len(); - if chunk_pos + 5 > data_len { - return Ok(None); - } - - let length = u32::from_be_bytes([ - self.data[chunk_pos], - self.data[chunk_pos + 1], - self.data[chunk_pos + 2], - self.data[chunk_pos + 3], - ]) as usize; - let compression_type = self.data[chunk_pos + 4]; - if length <= 1 { - return Ok(None); - } - - let compressed_length = length - 1; - if chunk_pos + 5 + compressed_length > data_len { - return Ok(None); - } - - let compressed_data = &self.data[chunk_pos + 5..chunk_pos + 5 + compressed_length]; - let decompressed = match compression_type { - 1 => { - let mut decoder = flate2::read::GzDecoder::new(compressed_data); - let mut buf = Vec::new(); - decoder - .read_to_end(&mut buf) - .map_err(|e| format!("gzip decompress failed: {}", e))?; - buf - } - 2 => { - let mut decoder = ZlibDecoder::new(compressed_data); - let mut buf = Vec::new(); - decoder - .read_to_end(&mut buf) - .map_err(|e| format!("zlib decompress failed: {}", e))?; - buf - } - _ => return Ok(None), - }; - - if decompressed.is_empty() { - return Ok(None); - } - - Ok(Some(decompressed)) - } -} - -pub struct JavaRegionFileWriter { - path: String, - buffer: Vec, - offsets: [i32; 1024], - timestamps: [i32; 1024], - next_sector: usize, -} - -impl JavaRegionFileWriter { - pub fn new(path: &str) -> Self { - let buffer = vec![0u8; SECTOR_BYTES * 2]; - let offsets = [0i32; 1024]; - let timestamps = [0i32; 1024]; - Self { - path: path.to_string(), - buffer, - offsets, - timestamps, - next_sector: 2, - } - } - - pub fn load_from_file(path: &str) -> Self { - if let Ok(data) = fs::read(path) { - let buffer = data.clone(); - let mut offsets = [0i32; 1024]; - let mut timestamps = [0i32; 1024]; - for i in 0..1024 { - let pos = i * 4; - if pos + 4 <= data.len() { - offsets[i] = i32::from_be_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]); - } - } - - for i in 0..1024 { - let pos = SECTOR_BYTES + i * 4; - if pos + 4 <= data.len() { - timestamps[i] = i32::from_be_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]); - } - } - - let mut max_sector = 2; - for &off in &offsets { - if off != 0 { - let sector = (off >> 8) as usize; - let count = (off & 0xFF) as usize; - let end = sector + count; - if end > max_sector { - max_sector = end; - } - } - } - - Self { - path: path.to_string(), - buffer, - offsets, - timestamps, - next_sector: max_sector, - } - } else { - Self::new(path) - } - } - - pub fn write_chunk(&mut self, local_x: i32, local_z: i32, uncompressed_nbt: &[u8]) { - if local_x < 0 || local_x > 31 || local_z < 0 || local_z > 31 { - return; - } - - let compressed = compress_zlib(uncompressed_nbt); - let payload_length = 1 + compressed.len(); - let total_length = 4 + payload_length; - let sectors_needed = (total_length + SECTOR_BYTES - 1) / SECTOR_BYTES; - if sectors_needed >= 256 { - return; - } - - let sector_start = self.next_sector; - self.next_sector += sectors_needed; - while self.buffer.len() < (sector_start + sectors_needed) * SECTOR_BYTES { - self.buffer.extend(std::iter::repeat(0u8).take(SECTOR_BYTES)); - } - - let write_pos = sector_start * SECTOR_BYTES; - self.buffer[write_pos..write_pos + 4] - .copy_from_slice(&(payload_length as u32).to_be_bytes()); - self.buffer[write_pos + 4] = 2; - self.buffer[write_pos + 5..write_pos + 5 + compressed.len()] - .copy_from_slice(&compressed); - - let padding = sectors_needed * SECTOR_BYTES - total_length; - if padding > 0 { - for i in 0..padding { - self.buffer[write_pos + total_length + i] = 0; - } - } - - let offset_index = (local_x & 31) + (local_z & 31) * 32; - self.offsets[offset_index as usize] = ((sector_start as i32) << 8) | (sectors_needed as i32); - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_secs() as i32; - self.timestamps[offset_index as usize] = now; - } - - pub fn save(&mut self) -> Result<(), String> { - while self.buffer.len() < self.next_sector * SECTOR_BYTES { - self.buffer.extend(std::iter::repeat(0u8).take(SECTOR_BYTES)); - } - - for i in 0..1024 { - let pos = i * 4; - self.buffer[pos..pos + 4].copy_from_slice(&(self.offsets[i] as u32).to_be_bytes()); - } - - for i in 0..1024 { - let pos = SECTOR_BYTES + i * 4; - self.buffer[pos..pos + 4] - .copy_from_slice(&(self.timestamps[i] as u32).to_be_bytes()); - } - - let total = self.next_sector * SECTOR_BYTES; - let data = &self.buffer[..total]; - if let Some(parent) = Path::new(&self.path).parent() { - fs::create_dir_all(parent) - .map_err(|e| format!("Failed to create region directory: {}", e))?; - } - - fs::write(&self.path, data) - .map_err(|e| format!("Failed to write region file: {}", e))?; - Ok(()) - } -} - -pub struct LceRegionFile { - filename: String, - data: Vec, - offsets: [i32; 1024], - timestamps: [i32; 1024], - region_x: i32, - region_z: i32, - sector_count: usize, -} - -impl LceRegionFile { - pub fn new(filename: &str) -> Self { - let (region_x, region_z) = parse_region_coordinates(filename); - let data = vec![0u8; SECTOR_BYTES * 2]; - Self { - filename: filename.to_string(), - data, - offsets: [0i32; 1024], - timestamps: [0i32; 1024], - region_x, - region_z, - sector_count: 2, - } - } - - pub fn write_chunk(&mut self, x: i32, z: i32, mut uncompressed_data: Vec) { - if x < 0 || x >= 32 || z < 0 || z >= 32 { - return; - } - if uncompressed_data.is_empty() { - return; - } - - uncompressed_data = force_chunk_coordinates( - &uncompressed_data, - self.region_x * 32 + x, - self.region_z * 32 + z, - ); - if uncompressed_data.is_empty() { - return; - } - - let compressed = compress_zlib_only(&uncompressed_data); - let total_size = 8 + compressed.len(); - let sectors_needed = (total_size + SECTOR_BYTES - 1) / SECTOR_BYTES; - if sectors_needed >= 256 { - return; - } - - let sector_number = self.sector_count; - self.sector_count += sectors_needed; - while self.data.len() < (sector_number + sectors_needed) * SECTOR_BYTES { - self.data.extend(std::iter::repeat(0u8).take(SECTOR_BYTES)); - } - - let write_pos = sector_number * SECTOR_BYTES; - let stored_length = compressed.len() as u32; - self.data[write_pos..write_pos + 4] - .copy_from_slice(&stored_length.to_le_bytes()); - self.data[write_pos + 4..write_pos + 8] - .copy_from_slice(&(uncompressed_data.len() as u32).to_le_bytes()); - self.data[write_pos + 8..write_pos + 8 + compressed.len()] - .copy_from_slice(&compressed); - - let padding = sectors_needed * SECTOR_BYTES - total_size; - if padding > 0 { - for i in 0..padding { - self.data[write_pos + total_size + i] = 0; - } - } - - let offset_index = (x + z * 32) as usize; - self.offsets[offset_index] = ((sector_number as i32) << 8) | (sectors_needed as i32); - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_secs() as i32; - self.timestamps[offset_index] = now; - } - - pub fn write_to_container(&mut self, container: &mut SaveDataContainer) { - let _sorted_entries: Vec<(usize, i32, i32)> = (0..1024) - .map(|i| (i, self.offsets[i], self.timestamps[i])) - .filter(|(_, off, _)| *off != 0) - .collect(); - - for i in 0..1024 { - let pos = i * 4; - self.data[pos..pos + 4].copy_from_slice(&(self.offsets[i] as u32).to_le_bytes()); - } - - for i in 0..1024 { - let pos = SECTOR_BYTES + i * 4; - self.data[pos..pos + 4] - .copy_from_slice(&(self.timestamps[i] as u32).to_le_bytes()); - } - - let total = self.sector_count * SECTOR_BYTES; - let region_bytes = self.data[..total].to_vec(); - let entry = container.create_file(&self.filename); - container.write_to_file(entry, ®ion_bytes); - } -} - -fn parse_region_coordinates(filename: &str) -> (i32, i32) { - let name = Path::new(filename) - .file_stem() - .unwrap_or_default() - .to_string_lossy() - .to_string(); - let parts: Vec<&str> = name.split('.').collect(); - if parts.len() < 3 { - return (0, 0); - } - let rx = parts[parts.len() - 2].parse().unwrap_or(0); - let rz = parts[parts.len() - 1].parse().unwrap_or(0); - (rx, rz) -} - -pub fn force_chunk_coordinates(data: &[u8], expected_x: i32, expected_z: i32) -> Vec { - if data.is_empty() { - return Vec::new(); - } - - if let Ok(mut compound) = nbt::read_nbt(data) { - if compound.get("Level").is_some() { - if let Some(nbt::NbtValue::Compound(c)) = compound.get_mut("Level") { - c.insert("xPos", NbtValue::Int(expected_x)); - c.insert("zPos", NbtValue::Int(expected_z)); - } - return nbt::write_nbt(&compound); - } - - compound.insert("xPos", NbtValue::Int(expected_x)); - compound.insert("zPos", NbtValue::Int(expected_z)); - let mut root = NbtCompound::new(""); - root.insert("Level", NbtValue::Compound(compound)); - nbt::write_nbt(&root) - } else if data.len() >= 10 { - let version = i16::from_be_bytes([data[0], data[1]]); - if version == 8 || version == 9 { - let mut patched = data.to_vec(); - patched[2..6].copy_from_slice(&expected_x.to_be_bytes()); - patched[6..10].copy_from_slice(&expected_z.to_be_bytes()); - return patched; - } - Vec::new() - } else { - Vec::new() - } -} - -pub struct SaveDataContainer { - original_save_version: i16, - current_save_version: i16, - entries: Vec, - blob: Vec, - data_end: usize, -} - -pub struct SaveFileEntry { - pub name: String, - pub length: u32, - pub start_offset: u32, - pub last_mod: i64, - pub current_pointer: u32, -} - -impl SaveDataContainer { - pub const FILE_ENTRY_SIZE: usize = 144; - pub fn new(original_save_version: i16, current_save_version: i16) -> Self { - Self { - original_save_version, - current_save_version, - entries: Vec::new(), - blob: vec![0u8; 2 * 1024 * 1024], - data_end: 12, - } - } - - pub fn create_file(&mut self, name: &str) -> usize { - if let Some(idx) = self.entries.iter().position(|e| e.name == name) { - return idx; - } - let entry = SaveFileEntry { - name: name.to_string(), - length: 0, - start_offset: self.data_end as u32, - last_mod: 0, - current_pointer: self.data_end as u32, - }; - self.entries.push(entry); - self.entries.len() - 1 - } - - pub fn write_to_file(&mut self, index: usize, data: &[u8]) { - if data.is_empty() { - return; - } - - let needs_reinit = self.entries[index].length == 0; - if needs_reinit { - self.entries[index].start_offset = self.data_end as u32; - self.entries[index].current_pointer = self.data_end as u32; - } - - let write_pos = self.entries[index].current_pointer as usize; - let end_pos = write_pos + data.len(); - self.ensure_capacity(end_pos); - self.blob[write_pos..write_pos + data.len()].copy_from_slice(data); - self.entries[index].current_pointer += data.len() as u32; - let written = self.entries[index].current_pointer - self.entries[index].start_offset; - if written > self.entries[index].length { - self.entries[index].length = written; - } - - let entry_end = (self.entries[index].start_offset + self.entries[index].length) as usize; - if entry_end > self.data_end { - self.data_end = entry_end; - } - - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as i64; - self.entries[index].last_mod = now; - } - - pub fn save(&mut self, output_path: &str) -> Result<(), String> { - self.write_header(); - let total_size = self.data_end + self.entries.len() * Self::FILE_ENTRY_SIZE; - self.ensure_capacity(total_size); - self.write_footer(); - let raw_blob = self.blob[..total_size].to_vec(); - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best()); - encoder - .write_all(&raw_blob) - .map_err(|e| format!("zlib compress failed: {}", e))?; - let compressed_data = encoder - .finish() - .map_err(|e| format!("zlib finish failed: {}", e))?; - - if let Some(parent) = Path::new(output_path).parent() { - fs::create_dir_all(parent) - .map_err(|e| format!("Failed to create output directory: {}", e))?; - } - - let mut file = fs::File::create(output_path) - .map_err(|e| format!("Failed to create output file: {}", e))?; - file.write_all(&(0u32).to_le_bytes()) - .map_err(|e| format!("write failed: {}", e))?; - file.write_all(&(total_size as u32).to_le_bytes()) - .map_err(|e| format!("write failed: {}", e))?; - file.write_all(&compressed_data) - .map_err(|e| format!("write failed: {}", e))?; - Ok(()) - } - - fn write_header(&mut self) { - self.blob[0..4] - .copy_from_slice(&(self.data_end as u32).to_le_bytes()); - self.blob[4..8] - .copy_from_slice(&(self.entries.len() as u32).to_le_bytes()); - self.blob[8..10] - .copy_from_slice(&self.original_save_version.to_le_bytes()); - self.blob[10..12] - .copy_from_slice(&self.current_save_version.to_le_bytes()); - } - - fn write_footer(&mut self) { - let mut sorted: Vec = (0..self.entries.len()).collect(); - sorted.sort_by_key(|&i| self.entries[i].start_offset); - let mut pos = self.data_end; - for &i in &sorted { - let entry = &self.entries[i]; - let mut name_bytes = vec![0u8; 128]; - let encoded: Vec = entry - .name - .encode_utf16() - .flat_map(|c| c.to_le_bytes()) - .collect(); - let copy_len = encoded.len().min(126); - name_bytes[..copy_len].copy_from_slice(&encoded[..copy_len]); - self.blob[pos..pos + 128].copy_from_slice(&name_bytes); - pos += 128; - self.blob[pos..pos + 4].copy_from_slice(&entry.length.to_le_bytes()); - pos += 4; - self.blob[pos..pos + 4].copy_from_slice(&entry.start_offset.to_le_bytes()); - pos += 4; - self.blob[pos..pos + 8].copy_from_slice(&entry.last_mod.to_le_bytes()); - pos += 8; - } - } - - fn ensure_capacity(&mut self, required: usize) { - if required <= self.blob.len() { - return; - } - let mut new_size = self.blob.len(); - while new_size < required { - new_size *= 2; - } - self.blob.resize(new_size, 0); - } -} - -pub fn compress_zlib(data: &[u8]) -> Vec { - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best()); - encoder.write_all(data).unwrap(); - encoder.finish().unwrap() -} - -pub fn compress_zlib_only(data: &[u8]) -> Vec { - compress_zlib(data) -} - -pub fn decompress_zlib(data: &[u8]) -> Result, String> { - let mut decoder = ZlibDecoder::new(data); - let mut buf = Vec::new(); - decoder.read_to_end(&mut buf).map_err(|e| format!("zlib decompress failed: {}", e))?; - Ok(buf) -} -/* -//neo: unused -pub fn decompress_rle_zlib(data: &[u8], decompressed_size: usize) -> Result, String> { - let rle_data = decompress_zlib(data)?; - Ok(rle_decode(&rle_data, decompressed_size)) -} - -pub fn rle_encode(data: &[u8]) -> Vec { - let mut out = Vec::new(); - let mut i = 0; - while i < data.len() { - let current = data[i]; - i += 1; - let mut count = 1usize; - while i < data.len() && data[i] == current && count < 256 { - i += 1; - count += 1; - } - - if count <= 3 { - if current == 0xFF { - out.push(0xFF); - out.push((count - 1) as u8); - } else { - for _ in 0..count { - out.push(current); - } - } - } else { - out.push(0xFF); - out.push((count - 1) as u8); - out.push(current); - } - } - out -} - -pub fn rle_decode(data: &[u8], expected_size: usize) -> Vec { - let mut output = vec![0u8; expected_size]; - let mut in_pos = 0; - let mut out_pos = 0; - while in_pos < data.len() && out_pos < expected_size { - let current = data[in_pos]; - in_pos += 1; - if current == 0xFF { - if in_pos >= data.len() { - break; - } - let count = data[in_pos] as usize; - in_pos += 1; - if count < 3 { - let run = count + 1; - for _ in 0..run { - if out_pos < expected_size { - output[out_pos] = 0xFF; - out_pos += 1; - } - } - } else { - let run = count + 1; - if in_pos >= data.len() { - break; - } - let value = data[in_pos]; - in_pos += 1; - for _ in 0..run { - if out_pos < expected_size { - output[out_pos] = value; - out_pos += 1; - } - } - } - } else { - output[out_pos] = current; - out_pos += 1; - } - } - - output -} -*/ diff --git a/src-tauri/src/commands/macos_setup.rs b/src-tauri/src/commands/macos_setup.rs deleted file mode 100644 index 0482891..0000000 --- a/src-tauri/src/commands/macos_setup.rs +++ /dev/null @@ -1,418 +0,0 @@ -//neo: thanks Huckle for the Intel macOS support reference code lol -use tauri::AppHandle; -#[cfg(target_os = "macos")] -use std::io::Write; -#[cfg(target_os = "macos")] -use std::process::Command; -#[cfg(target_os = "macos")] -use std::process::Stdio; -#[cfg(target_os = "macos")] -use futures_util::StreamExt; -#[cfg(target_os = "macos")] -use tauri::Emitter; -#[cfg(target_os = "macos")] -use serde::Deserialize; -#[cfg(target_os = "macos")] -use crate::platform::macos; -#[cfg(target_os = "macos")] -use crate::util; -#[cfg(target_os = "macos")] -use std::fs; - -#[tauri::command] -pub fn check_macos_runtime_installed(_app: AppHandle) -> bool { - #[cfg(target_os = "macos")] - { macos::is_macos_runtime_installed(&_app) } - #[cfg(not(target_os = "macos"))] - { false } -} - -#[tauri::command] -pub fn check_macos_runtime_installed_fast(_app: AppHandle) -> bool { - #[cfg(target_os = "macos")] - { macos::is_macos_runtime_installed(&_app) } - #[cfg(not(target_os = "macos"))] - { false } -} - -#[tauri::command] -pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Result<(), String> { - #[cfg(not(target_os = "macos"))] - { - let _ = window; - let _ = app; - return Err("macOS runtime setup is only supported on macOS.".into()); - } - - #[cfg(target_os = "macos")] - { - #[derive(Deserialize)] - struct GithubAsset { - name: String, - browser_download_url: String, - } - - #[derive(Deserialize)] - struct GithubRelease { - tag_name: String, - assets: Vec, - } - - let is_intel = std::env::consts::ARCH == "x86_64"; - - let repo = if is_intel { - "Gcenx/macOS_Wine_builds" - } else { - "Gcenx/game-porting-toolkit" - }; - - macos::emit_macos_setup_progress( - &window, - "resolving", - "Resolving macOS compatibility runtime…".into(), - None, - ); - - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let release_text = client - .get(format!("https://api.github.com/repos/{}/releases/latest", repo)) - .header("User-Agent", "Emerald-Legacy-Launcher") - .send() - .await - .map_err(|e| e.to_string())? - .error_for_status() - .map_err(|e| e.to_string())? - .text() - .await - .map_err(|e| e.to_string())?; - - let release: GithubRelease = - serde_json::from_str(&release_text).map_err(|e| e.to_string())?; - let asset = release - .assets - .iter() - .find(|a| { - let is_archive = - a.name.ends_with(".tar.xz") || a.name.ends_with(".tar.gz"); - if is_intel { - is_archive && a.name.contains("staging") - } else { - is_archive - } - }) - .ok_or_else(|| "No compatible runtime asset found in latest release.".to_string())?; - - let runtime_dir = macos::get_macos_runtime_dir(&app); - let toolkit_dir = runtime_dir.join("toolkit"); - let prefix_dir = runtime_dir.join("prefix"); - fs::create_dir_all(&runtime_dir).map_err(|e| e.to_string())?; - if toolkit_dir.exists() { - let _ = fs::remove_dir_all(&toolkit_dir); - } - fs::create_dir_all(&toolkit_dir).map_err(|e| e.to_string())?; - - macos::emit_macos_setup_progress( - &window, - "downloading", - format!("Downloading runtime ({})…", release.tag_name), - Some(0.0), - ); - - let archive_path = runtime_dir.join(format!("gptk_{}", asset.name)); - let response = client - .get(&asset.browser_download_url) - .header("User-Agent", "Emerald-Legacy-Launcher") - .send() - .await - .map_err(|e| e.to_string())? - .error_for_status() - .map_err(|e| e.to_string())?; - - let total_size = response.content_length().unwrap_or(0) as f64; - let mut file = fs::File::create(&archive_path).map_err(|e| e.to_string())?; - let mut downloaded = 0.0; - let mut last_percent_sent: i64 = -1; - let mut stream = response.bytes_stream(); - while let Some(chunk) = stream.next().await { - let chunk = chunk.map_err(|e| e.to_string())?; - file.write_all(&chunk).map_err(|e| e.to_string())?; - downloaded += chunk.len() as f64; - if total_size > 0.0 { - let percent = (downloaded / total_size * 100.0).clamp(0.0, 100.0); - let rounded = percent.floor() as i64; - if rounded != last_percent_sent { - last_percent_sent = rounded; - macos::emit_macos_setup_progress( - &window, - "downloading", - format!("Downloading runtime… {}%", rounded), - Some(percent), - ); - } - } - } - drop(file); - macos::emit_macos_setup_progress( - &window, - "extracting", - "Extracting runtime…".into(), - None, - ); - - let archive_metadata = - fs::metadata(&archive_path).map_err(|e| format!("Cannot read archive: {}", e))?; - println!("Archive size: {} bytes", archive_metadata.len()); - if archive_metadata.len() < 100_000_000 { - return Err(format!("Archive too small: {} bytes", archive_metadata.len())); - } - - let status = Command::new("tar") - .args([ - "-xf", - archive_path - .to_str() - .ok_or_else(|| "Invalid archive path".to_string())?, - "-C", - toolkit_dir - .to_str() - .ok_or_else(|| "Invalid toolkit path".to_string())?, - ]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::piped()) - .status() - .map_err(|e| e.to_string())?; - - println!("Tar exit status: {:?}", status); - let _ = fs::remove_file(&archive_path); - if !status.success() { - return Err(format!("Extraction failed with status: {:?}", status)); - } - - fs::create_dir_all(&prefix_dir).map_err(|e| e.to_string())?; - let wine_binary = if is_intel { - macos::find_executable_recursive(&toolkit_dir, "wine") - .or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine64")) - } else { - macos::find_executable_recursive(&toolkit_dir, "wine64") - .or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine")) - } - .ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?; - - let wine_bin_dir = wine_binary - .parent() - .map(|pp| pp.to_path_buf()) - .ok_or_else(|| "Unable to locate wine bin directory inside runtime.".to_string())?; - - macos::emit_macos_setup_progress( - &window, - "initializing", - "Initializing Wine prefix…".into(), - None, - ); - - let mut cmd = Command::new(&wine_binary); - cmd.arg("wineboot"); - cmd.arg("-u"); - cmd.env("WINEPREFIX", &prefix_dir); - cmd.env("WINEARCH", "win64"); - cmd.env("WINEDEBUG", "-all"); - cmd.env("WINEESYNC", "1"); - cmd.env("WINEDLLOVERRIDES", "winemenubuilder.exe=d;mscoree,mshtml="); - cmd.env("MTL_HUD_ENABLED", "0"); - cmd.env( - "PATH", - format!( - "{}:{}", - wine_bin_dir.to_string_lossy(), - std::env::var("PATH").unwrap_or_default() - ), - ); - cmd.stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); - - let status = cmd.status().map_err(|e| e.to_string())?; - if !status.success() { - return Err("Wine prefix initialization failed".into()); - } - - if is_intel { - macos::emit_macos_setup_progress( - &window, - "dxvk", - "Fetching latest DXVK…".into(), - None, - ); - - #[derive(Deserialize)] - struct DxvkAsset { - name: String, - browser_download_url: String, - } - - #[derive(Deserialize)] - struct DxvkRelease { - assets: Vec, - } - - let dxvk_release_text = client - .get("https://api.github.com/repos/Gcenx/DXVK-macOS/releases/latest") - .header("User-Agent", "Emerald-Legacy-Launcher") - .send() - .await - .map_err(|e| e.to_string())? - .error_for_status() - .map_err(|e| e.to_string())? - .text() - .await - .map_err(|e| e.to_string())?; - - let dxvk_release: DxvkRelease = - serde_json::from_str(&dxvk_release_text).map_err(|e| e.to_string())?; - let dxvk_asset = dxvk_release - .assets - .iter() - .find(|a| { - let is_archive = - a.name.ends_with(".tar.xz") || a.name.ends_with(".tar.gz"); - is_archive && !a.name.contains("builtin") - }) - .ok_or_else(|| "No compatible DXVK asset found.".to_string())?; - - macos::emit_macos_setup_progress( - &window, - "dxvk_downloading", - "Downloading DXVK…".into(), - Some(0.0), - ); - - let dxvk_archive_path = runtime_dir.join(format!("dxvk_{}", dxvk_asset.name)); - let dxvk_response = client - .get(&dxvk_asset.browser_download_url) - .header("User-Agent", "Emerald-Legacy-Launcher") - .send() - .await - .map_err(|e| e.to_string())? - .error_for_status() - .map_err(|e| e.to_string())?; - - let dxvk_total = dxvk_response.content_length().unwrap_or(0) as f64; - let mut dxvk_file = fs::File::create(&dxvk_archive_path).map_err(|e| e.to_string())?; - let mut dxvk_downloaded = 0.0; - let mut dxvk_last_percent: i64 = -1; - let mut dxvk_stream = dxvk_response.bytes_stream(); - while let Some(chunk) = dxvk_stream.next().await { - let chunk = chunk.map_err(|e| e.to_string())?; - dxvk_file.write_all(&chunk).map_err(|e| e.to_string())?; - dxvk_downloaded += chunk.len() as f64; - if dxvk_total > 0.0 { - let percent = (dxvk_downloaded / dxvk_total * 100.0).clamp(0.0, 100.0); - let rounded = percent.floor() as i64; - if rounded != dxvk_last_percent { - dxvk_last_percent = rounded; - macos::emit_macos_setup_progress( - &window, - "dxvk_downloading", - format!("Downloading DXVK… {}%", rounded), - Some(percent), - ); - } - } - } - drop(dxvk_file); - macos::emit_macos_setup_progress( - &window, - "dxvk_extracting", - "Extracting DXVK…".into(), - None, - ); - - let dxvk_dir = runtime_dir.join("dxvk"); - fs::create_dir_all(&dxvk_dir).map_err(|e| e.to_string())?; - let status = Command::new("tar") - .args([ - "-xf", - dxvk_archive_path - .to_str() - .ok_or_else(|| "Invalid DXVK archive path".to_string())?, - "-C", - dxvk_dir - .to_str() - .ok_or_else(|| "Invalid DXVK extraction path".to_string())?, - ]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::piped()) - .status() - .map_err(|e| e.to_string())?; - let _ = fs::remove_file(&dxvk_archive_path); - if !status.success() { - return Err(format!("DXVK extraction failed with status: {:?}", status)); - } - - macos::emit_macos_setup_progress( - &window, - "dxvk_patching", - "Patching runtime with DXVK…".into(), - None, - ); - - let system32 = prefix_dir.join("drive_c/windows/system32"); - let syswow64 = prefix_dir.join("drive_c/windows/syswow64"); - let _ = fs::create_dir_all(&system32); - let _ = fs::create_dir_all(&syswow64); - let copy_dir = |src_dir: &std::path::Path, dst_dir: &std::path::Path| -> Result<(), String> { - if !src_dir.exists() { - return Ok(()); - } - for entry in fs::read_dir(src_dir).map_err(|e| e.to_string())? { - let entry = entry.map_err(|e| e.to_string())?; - let path = entry.path(); - if path.extension().and_then(|e| e.to_str()) == Some("dll") { - let dest = dst_dir.join(path.file_name().unwrap()); - fs::copy(&path, &dest).map_err(|e| e.to_string())?; - } - } - Ok(()) - }; - - let dxvk_x64 = dxvk_dir.join("x64"); - let dxvk_x32 = dxvk_dir.join("x32"); - copy_dir(&dxvk_x64, &system32)?; - copy_dir(&dxvk_x32, &syswow64)?; - for dll_name in &["d3d11", "dxgi"] { - let mut reg_cmd = Command::new(&wine_binary); - reg_cmd - .args(["reg", "add", "HKCU\\Software\\Wine\\DllOverrides"]) - .arg("/v") - .arg(dll_name) - .arg("/t") - .arg("REG_SZ") - .arg("/d") - .arg("native,builtin") - .arg("/f"); - reg_cmd - .env("WINEPREFIX", &prefix_dir) - .env("WINEDEBUG", "-all") - .env( - "PATH", - format!( - "{}:{}", - wine_bin_dir.to_string_lossy(), - std::env::var("PATH").unwrap_or_default() - ), - ) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); - let _ = reg_cmd.status(); - } - - let _ = fs::remove_dir_all(&dxvk_dir); - } - - macos::emit_macos_setup_progress(&window, "done", "Setup complete.".into(), Some(100.0)); - Ok(()) - } -} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs deleted file mode 100644 index 379e62f..0000000 --- a/src-tauri/src/commands/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod config; -pub mod console2lce; -pub mod dlc; -pub mod download; -pub mod file_dialogs; -pub mod game; -pub mod goldmapper; -pub mod java2lce; -pub mod macos_setup; -pub mod platform; -pub mod plugins; -pub mod proxy_cmd; -pub mod runners; -pub mod skin; -pub mod steam; -pub mod workshop; diff --git a/src-tauri/src/commands/platform.rs b/src-tauri/src/commands/platform.rs deleted file mode 100644 index 890a48b..0000000 --- a/src-tauri/src/commands/platform.rs +++ /dev/null @@ -1,32 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct PlatformInfo { - pub is_linux: bool, - pub is_mac: bool, - pub is_windows: bool, - pub is_android: bool, - pub arch: String, -} - -#[tauri::command] -pub fn get_platform() -> PlatformInfo { - let arch = std::env::consts::ARCH.to_string(); - #[cfg(target_os = "linux")] - { - PlatformInfo { is_linux: true, is_mac: false, is_windows: false, is_android: false, arch } - } - #[cfg(target_os = "macos")] - { - PlatformInfo { is_linux: false, is_mac: true, is_windows: false, is_android: false, arch } - } - #[cfg(target_os = "windows")] - { - PlatformInfo { is_linux: false, is_mac: false, is_windows: true, is_android: false, arch } - } - #[cfg(target_os = "android")] - { - PlatformInfo { is_linux: false, is_mac: false, is_windows: false, is_android: true, arch } - } -} diff --git a/src-tauri/src/commands/plugins.rs b/src-tauri/src/commands/plugins.rs deleted file mode 100644 index 9fdf26a..0000000 --- a/src-tauri/src/commands/plugins.rs +++ /dev/null @@ -1,48 +0,0 @@ -use serde::Serialize; -use std::fs; -#[derive(Serialize)] -pub struct DirEntry { - pub name: String, - pub is_dir: bool, -} - -#[tauri::command] -pub fn get_plugins_dir(app: tauri::AppHandle) -> Result { - let dir = crate::util::get_app_dir(&app).join("plugins"); - fs::create_dir_all(&dir).map_err(|e| e.to_string())?; - Ok(dir.to_string_lossy().to_string()) -} - -#[tauri::command] -pub fn list_directory(path: String) -> Result, String> { - let entries = fs::read_dir(&path).map_err(|e| e.to_string())?; - let mut results = Vec::new(); - for entry in entries { - let entry = entry.map_err(|e| e.to_string())?; - results.push(DirEntry { - name: entry.file_name().to_string_lossy().to_string(), - is_dir: entry.file_type().map(|t| t.is_dir()).unwrap_or(false), - }); - } - Ok(results) -} - -#[tauri::command] -pub fn create_plugin_dir(app: tauri::AppHandle, plugin_id: String) -> Result { - let dir = crate::util::get_app_dir(&app) - .join("plugins") - .join(&plugin_id); - fs::create_dir_all(&dir).map_err(|e| e.to_string())?; - Ok(dir.to_string_lossy().to_string()) -} - -#[tauri::command] -pub fn remove_plugin_dir(app: tauri::AppHandle, plugin_id: String) -> Result<(), String> { - let dir = crate::util::get_app_dir(&app) - .join("plugins") - .join(&plugin_id); - if dir.exists() { - fs::remove_dir_all(&dir).map_err(|e| e.to_string())?; - } - Ok(()) -} diff --git a/src-tauri/src/commands/proxy_cmd.rs b/src-tauri/src/commands/proxy_cmd.rs deleted file mode 100644 index a516815..0000000 --- a/src-tauri/src/commands/proxy_cmd.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::types::HttpResponse; -use crate::util; -#[tauri::command] -pub async fn http_proxy_request( - app: tauri::AppHandle, - method: String, - url: String, - body: Option, - headers: std::collections::HashMap, -) -> Result { - let client = util::build_http_client_from_app(&app)?; - let mut req = match method.to_uppercase().as_str() { - "GET" => client.get(&url), - "POST" => client.post(&url), - "PUT" => client.put(&url), - "DELETE" => client.delete(&url), - _ => return Err(format!("Unsupported method: {}", method)), - }; - for (k, v) in headers { - req = req.header(k, v); - } - if let Some(b) = body { - req = req.body(b); - } - let res = req.send().await.map_err(|e| e.to_string())?; - let status = res.status().as_u16(); - let text = res.text().await.map_err(|e| e.to_string())?; - Ok(HttpResponse { - status, - body: text, - }) -} diff --git a/src-tauri/src/commands/runners.rs b/src-tauri/src/commands/runners.rs deleted file mode 100644 index 6965d96..0000000 --- a/src-tauri/src/commands/runners.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::fs; -use std::process::Command; -use tauri::AppHandle; -use crate::types::Runner; -use crate::util; -#[tauri::command] -pub fn get_available_runners(app: AppHandle) -> Vec { - let mut runners = Vec::new(); - let mut seen_paths: std::collections::HashSet = std::collections::HashSet::new(); - #[cfg(target_os = "linux")] - { - if let Ok(output) = Command::new("which").arg("wine").output() { - if output.status.success() { - let path = String::from_utf8_lossy(&output.stdout).trim().to_string(); - if !seen_paths.contains(&path) { - seen_paths.insert(path.clone()); - runners.push(Runner { - id: "wine".to_string(), - name: "System Wine".to_string(), - path, - r#type: "wine".to_string(), - }); - } - } - } - - if let Ok(output) = Command::new("ls") - .arg("/usr/share/emerald-legacy-launcher/wine/bin/wine") - .output() - { - if output.status.success() { - let path = String::from_utf8_lossy(&output.stdout).trim().to_string(); - if !seen_paths.contains(&path) { - seen_paths.insert(path.clone()); - runners.push(Runner { - id: "flatpaksucks".to_string(), - name: "Default for Flatpak".to_string(), - path, - r#type: "wine".to_string(), - }); - } - } - } - - let home = std::env::var("HOME").unwrap_or_default(); - let steam_paths = [ - format!("{}/.local/share/Steam/compatibilitytools.d", home), - format!("{}/.local/share/Steam/steamapps/common", home), - "/usr/share/Steam/compatibilitytools.d".to_string() - ]; - - for base_path in steam_paths { - if let Ok(entries) = fs::read_dir(base_path) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - let name = entry.file_name().to_string_lossy().to_string(); - if name.to_lowercase().contains("proton") { - let path_str = path.to_string_lossy().to_string(); - if !seen_paths.contains(&path_str) { - seen_paths.insert(path_str.clone()); - runners.push(Runner { - id: format!("proton_{}", name), - name: name, - path: path_str, - r#type: "proton".to_string(), - }); - } - } - } - } - } - } - - let runners_dir = util::get_app_dir(&app).join("runners"); - let _ = fs::create_dir_all(&runners_dir); - if let Ok(entries) = fs::read_dir(&runners_dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - let dir_name = entry.file_name().to_string_lossy().to_string(); - let wine_bin = path.join("bin").join("wine"); - let proton_bin = path.join("proton"); - if proton_bin.exists() { - let path_str = path.to_string_lossy().to_string(); - if !seen_paths.contains(&path_str) { - seen_paths.insert(path_str.clone()); - runners.push(Runner { - id: format!("downloaded_{}", dir_name), - name: format!("{} (downloaded)", dir_name), - path: path_str, - r#type: "proton".to_string(), - }); - } - } else if wine_bin.exists() { - let path_str = wine_bin.to_string_lossy().to_string(); - if !seen_paths.contains(&path_str) { - seen_paths.insert(path_str.clone()); - runners.push(Runner { - id: format!("downloaded_{}", dir_name), - name: format!("{} (downloaded)", dir_name), - path: path_str, - r#type: "wine".to_string(), - }); - } - } - } - } - } - } - - runners -} diff --git a/src-tauri/src/commands/skin.rs b/src-tauri/src/commands/skin.rs deleted file mode 100644 index c97cc8a..0000000 --- a/src-tauri/src/commands/skin.rs +++ /dev/null @@ -1,197 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use tauri::AppHandle; -use tauri_plugin_opener::OpenerExt; -use base64::Engine; -use crate::types::ScreenshotInfo; -use crate::config; -use crate::util; -#[tauri::command] -pub async fn fetch_skin(app: AppHandle, username: String) -> Result<(String, String), String> { - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let mojang_url = format!("https://api.mojang.com/users/profiles/minecraft/{}", username); - let mojang_res = client.get(&mojang_url).send().await.map_err(|e| format!("Failed request to mojang: {}", e))?; - if !mojang_res.status().is_success() { - return Err("Player not found".to_string()); - } - let mojang_text = mojang_res.text().await.map_err(|e| format!("Failed to read mojang text: {}", e))?; - let mojang_data: serde_json::Value = serde_json::from_str(&mojang_text).map_err(|e| format!("Invalid Mojang JSON: {}", e))?; - let id = mojang_data.get("id").and_then(|v| v.as_str()).ok_or_else(|| "Invalid Moajng response format".to_string())?; - let name_exact = mojang_data.get("name").and_then(|v| v.as_str()).unwrap_or(&username).to_string(); - let mc_api_url = format!("https://api.minecraftapi.net/v3/profile/{}", id); - let mc_api_res = client.get(&mc_api_url).send().await.map_err(|e| format!("Failed request to mc api: {}", e))?; - if !mc_api_res.status().is_success() { - return Err("Error fetching skin data".to_string()); - } - let mc_api_text = mc_api_res.text().await.map_err(|e| format!("Failed to read mc api text: {}", e))?; - let mc_api_data: serde_json::Value = serde_json::from_str(&mc_api_text).map_err(|e| format!("Invalid MC API JSON: {}", e))?; - if let Some(b64) = mc_api_data.get("skin") - .and_then(|s| s.get("image")) - .and_then(|v| v.as_str()) - { - return Ok((b64.to_string(), name_exact)); - } - let skin_url = mc_api_data.get("skin") - .and_then(|s| s.get("url")) - .and_then(|v| v.as_str()) - .ok_or_else(|| "No skin found".to_string())?; - let skin_resp = client.get(skin_url).send().await.map_err(|e| format!("Failed to fetch skin image: {}", e))?; - if !skin_resp.status().is_success() { - return Err(format!("Failed to download skin image: {}", skin_resp.status())); - } - let skin_bytes = skin_resp.bytes().await.map_err(|e| format!("Failed to read skin image bytes: {}", e))?; - let image_b64 = base64::engine::general_purpose::STANDARD.encode(&skin_bytes); - Ok((image_b64, name_exact)) -} - -#[tauri::command] -pub async fn download_logo(app: AppHandle, id: String, url: String) -> Result { - let logos_dir = util::get_app_dir(&app).join("logos"); - fs::create_dir_all(&logos_dir).map_err(|e| e.to_string())?; - let file_ext = if url.to_lowercase().ends_with(".png") { - "png" - } else if url.to_lowercase().ends_with(".jpg") || url.to_lowercase().ends_with(".jpeg") { - "jpg" - } else { - "png" - }; - - let filename = format!("{}.{}", id, file_ext); - let dest_path = logos_dir.join(&filename); - let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?; - let response = client.get(&url).send().await.map_err(|e| e.to_string())?; - if !response.status().is_success() { - return Err(format!("Failed to download logo: {}", response.status())); - } - - let bytes = response.bytes().await.map_err(|e| e.to_string())?; - fs::write(&dest_path, bytes).map_err(|e| e.to_string())?; - Ok(dest_path.to_string_lossy().to_string()) -} - -#[tauri::command] -pub fn get_screenshots(app: AppHandle) -> Vec { - let mut screenshots = Vec::new(); - let root = util::get_app_dir(&app); - let mut instance_dirs = vec![root.join("instances")]; - let config_val = config::load_config_raw(app.clone()); - if let Some(ref editions) = config_val.custom_editions { - for ed in editions { - if let Some(path) = &ed.path { - instance_dirs.push(PathBuf::from(path)); - } - } - } - - for base_dir in instance_dirs { - if base_dir.ends_with("instances") { - if let Ok(entries) = fs::read_dir(&base_dir) { - for entry in entries.flatten() { - if entry.path().is_dir() { - let instance_id = entry.file_name().to_string_lossy().to_string(); - let dirs_to_check = [ - entry.path().join("screenshots"), - entry.path().join("Windows64").join("GameHDD"), - ]; - for screenshots_dir in dirs_to_check { - if let Ok(files) = fs::read_dir(screenshots_dir) { - for file in files.flatten() { - let path = file.path(); - if path.extension().and_then(|s| s.to_str()) == Some("png") { - let name = path.file_name().unwrap_or_default().to_string_lossy().to_string(); - let date = path.metadata().and_then(|m| m.modified()).ok() - .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) - .map(|d| d.as_secs()) - .unwrap_or(0); - screenshots.push(ScreenshotInfo { - path: path.to_string_lossy().to_string(), - instance_id: instance_id.clone(), - name, - date, - }); - } - } - } - } - } - } - } - } else { - let instance_id = base_dir.file_name().and_then(|n| n.to_str()).unwrap_or("custom").to_string(); - let final_id = config_val.custom_editions.as_ref() - .and_then(|eds| eds.iter().find(|e| e.path.as_deref() == base_dir.to_str()).map(|e| e.id.clone())) - .unwrap_or(instance_id); - - let dirs_to_check = [ - base_dir.join("screenshots"), - base_dir.join("Windows64").join("GameHDD"), - ]; - for screenshots_dir in dirs_to_check { - if let Ok(files) = fs::read_dir(screenshots_dir) { - for file in files.flatten() { - let path = file.path(); - if path.extension().and_then(|s| s.to_str()) == Some("png") { - let name = path.file_name().unwrap_or_default().to_string_lossy().to_string(); - let date = path.metadata().and_then(|m| m.modified()).ok() - .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) - .map(|d| d.as_secs()) - .unwrap_or(0); - screenshots.push(ScreenshotInfo { - path: path.to_string_lossy().to_string(), - instance_id: final_id.clone(), - name, - date, - }); - } - } - } - } - } - } - screenshots.sort_by(|a, b| b.date.cmp(&a.date)); - screenshots -} - -#[tauri::command] -pub fn delete_screenshot(path: String) -> Result<(), String> { - fs::remove_file(path).map_err(|e| e.to_string()) -} - -#[tauri::command] -pub fn open_screenshot_folder(app: AppHandle, path: String) { - let p = std::path::Path::new(&path); - if let Some(parent) = p.parent() { - if parent.exists() { - let _ = app.opener().open_path(parent.to_str().unwrap(), None::<&str>); - } - } -} - -#[tauri::command] -pub async fn save_global_skin_pck(app: AppHandle, pck_data: Vec) -> Result<(), String> { - let app_dir = util::get_app_dir(&app); - let _ = fs::write(app_dir.join("Skin.pck"), pck_data); - Ok(()) -} - -#[tauri::command] -pub fn read_screenshot_as_data_url(path: String) -> Result { - let data = fs::read(&path).map_err(|e| e.to_string())?; - let mime = if path.to_lowercase().ends_with(".png") { - "image/png" - } else if path.to_lowercase().ends_with(".jpg") || path.to_lowercase().ends_with(".jpeg") { - "image/jpeg" - } else if path.to_lowercase().ends_with(".gif") { - "image/gif" - } else if path.to_lowercase().ends_with(".webp") { - "image/webp" - } else if data.len() > 4 && data[..4] == [0x89, 0x50, 0x4E, 0x47] { - "image/png" - } else if data.len() > 2 && data[..2] == [0xFF, 0xD8] { - "image/jpeg" - } else { - "image/png" - }; - let b64 = base64::engine::general_purpose::STANDARD.encode(&data); - Ok(format!("data:{};base64,{}", mime, b64)) -} diff --git a/src-tauri/src/commands/steam.rs b/src-tauri/src/commands/steam.rs deleted file mode 100644 index 54e88a3..0000000 --- a/src-tauri/src/commands/steam.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use base64::Engine; -use steam_shortcuts_util::{Shortcut, parse_shortcuts, shortcuts_to_bytes}; -use tauri::AppHandle; -#[tauri::command] -pub async fn add_to_steam( - _app: AppHandle, - instance_id: String, - name: String, - title_base64: String, - panorama_base64: String, -) -> Result<(), String> { - let in_flatpak = std::path::Path::new("/.flatpak-info").exists(); - let (exe_str, launch_options, start_dir) = if in_flatpak { - ( - "/usr/bin/flatpak".to_string(), - format!("run io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher \"{}\"", instance_id), //neo: yes i'm hardcoding it lmfao - std::env::var("HOME").unwrap_or_default(), - ) - } else { - let exe_path = std::env::current_exe().map_err(|e| e.to_string())?; - let s = exe_path.to_string_lossy().to_string(); - let dir = exe_path.parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default(); - (s, format!("\"{}\"", instance_id), dir) - }; - let app_id_32 = steam_shortcuts_util::app_id_generator::calculate_app_id(&exe_str, &name); - let mut userdata_dirs: Vec = Vec::new(); - #[cfg(target_os = "linux")] - { - if let Ok(home) = std::env::var("HOME") { - let h = PathBuf::from(home); - userdata_dirs.push(h.join(".steam/steam/userdata")); - userdata_dirs.push(h.join(".local/share/Steam/userdata")); - userdata_dirs.push(h.join(".var/app/com.valvesoftware.Steam/.local/share/Steam/userdata")); - } - } - #[cfg(target_os = "windows")] - { - userdata_dirs.push(PathBuf::from("C:\\Program Files\\Steam\\userdata")); - userdata_dirs.push(PathBuf::from("C:\\Program Files (x86)\\Steam\\userdata")); - } - #[cfg(target_os = "macos")] - { - if let Ok(home) = std::env::var("HOME") { - let h = PathBuf::from(home); - userdata_dirs.push(h.join("Library/Application Support/Steam/userdata")); - } - } - - let valid_userdata_dirs: Vec = userdata_dirs.into_iter().filter(|d| d.exists()).collect(); - if valid_userdata_dirs.is_empty() { - return Err("Steam userdata directory not found.".into()); - } - - for userdata_root in valid_userdata_dirs { - let entries = fs::read_dir(&userdata_root).map_err(|e| e.to_string())?; - for entry in entries.flatten() { - if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { - let user_config_dir = entry.path().join("config"); - let shortcuts_path = user_config_dir.join("shortcuts.vdf"); - if !user_config_dir.exists() { continue; } - let content = if shortcuts_path.exists() { - fs::read(&shortcuts_path).unwrap_or_default() - } else { - Vec::new() - }; - - let shortcuts = if !content.is_empty() { - parse_shortcuts(&content).map_err(|e| e.to_string())? - } else { - Vec::new() - }; - - let mut owned_shortcuts: Vec = shortcuts.iter().map(|s| s.to_owned()).collect(); - if owned_shortcuts.iter().any(|s| s.app_name == name && s.exe == exe_str) { - continue; - } - - owned_shortcuts.push(steam_shortcuts_util::shortcut::ShortcutOwned { - order: owned_shortcuts.len().to_string(), - app_id: app_id_32, - app_name: name.clone(), - exe: exe_str.clone(), - start_dir: start_dir.clone(), - icon: "".to_string(), - shortcut_path: "".to_string(), - launch_options: launch_options.clone(), - is_hidden: false, - allow_desktop_config: true, - allow_overlay: true, - open_vr: 0, - dev_kit: 0, - dev_kit_game_id: "".to_string(), - dev_kit_overrite_app_id: 0, - last_play_time: 0, - tags: Vec::new(), - }); - - let final_shortcuts: Vec = owned_shortcuts.iter().map(|s| s.borrow()).collect(); - let new_content = shortcuts_to_bytes(&final_shortcuts); - fs::write(&shortcuts_path, new_content).map_err(|e| e.to_string())?; - let grid_dir = user_config_dir.join("grid"); - if !grid_dir.exists() { - let _ = fs::create_dir_all(&grid_dir); - } - - if grid_dir.exists() { - let panorama_data = base64::engine::general_purpose::STANDARD.decode(panorama_base64.clone()).map_err(|e| e.to_string())?; - let title_data = base64::engine::general_purpose::STANDARD.decode(title_base64.clone()).map_err(|e| e.to_string())?; - let _ = fs::write(grid_dir.join(format!("{}p.png", app_id_32)), &panorama_data); - let _ = fs::write(grid_dir.join(format!("{}_hero.png", app_id_32)), &panorama_data); - let _ = fs::write(grid_dir.join(format!("{}.png", app_id_32)), &panorama_data); - let _ = fs::write(grid_dir.join(format!("{}_logo.png", app_id_32)), &title_data); - let _ = fs::write(grid_dir.join(format!("{}.json", app_id_32)), "{\"nVersion\":1,\"logoPosition\":{\"pinnedPosition\":\"CenterCenter\",\"nWidthPct\":50,\"nHeightPct\":50}}".as_bytes()); - } - } - } - } - - Ok(()) -} diff --git a/src-tauri/src/commands/workshop.rs b/src-tauri/src/commands/workshop.rs deleted file mode 100644 index 8bf5220..0000000 --- a/src-tauri/src/commands/workshop.rs +++ /dev/null @@ -1,404 +0,0 @@ -use std::fs; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; -use tauri::{AppHandle, Emitter}; -use crate::types::{WorkshopInstallRequest, InstalledWorkshopPackage, InstalledPackageEntry}; -use crate::config; -use crate::util; -use super::download::DownloadProgress; -fn group_archives(zips: &std::collections::HashMap) -> Vec<(Vec, String)> { - let mut groups: Vec<(Vec, String)> = Vec::new(); - let mut consumed: std::collections::HashSet = std::collections::HashSet::new(); - let mut entries: Vec<(&String, &String)> = zips.iter().collect(); - entries.sort_by(|a, b| a.0.cmp(b.0)); - for &(name, dest) in &entries { - if consumed.contains(name) { - continue; - } - if !name.to_lowercase().ends_with(".zip") { - continue; - } - let base = &name[..name.len() - 4]; - let mut parts = vec![name.clone()]; - consumed.insert(name.clone()); - let mut n = 1; - loop { - let candidate = format!("{}.z{:02}", base, n); - if zips.contains_key(&candidate) { - parts.push(candidate.clone()); - consumed.insert(candidate); - n += 1; - } else { - break; - } - } - if parts.len() == 1 { - let mut n = 1; - loop { - let candidate = format!("{}.zip.{:03}", base, n); - if zips.contains_key(&candidate) { - parts.push(candidate.clone()); - consumed.insert(candidate); - n += 1; - } else { - break; - } - } - } - groups.push((parts, dest.clone())); - } - - for &(name, dest) in &entries { - if !consumed.contains(name) { - consumed.insert(name.clone()); - groups.push((vec![name.clone()], dest.clone())); - } - } - groups -} - -async fn download_and_assemble( - app: &AppHandle, - tmp_dir: &Path, - parts: &[String], - raw_base: &str, - package_id: &str, - done: &mut usize, - total: usize, -) -> Result { - let mut downloaded: Vec = Vec::new(); - for part in parts { - let url = format!("{}/{}", raw_base, part); - let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?; - let response = client.get(&url).send().await.map_err(|e| e.to_string())?; - if !response.status().is_success() { - return Err(format!("Failed to download {}: HTTP {}", part, response.status())); - } - let bytes = response.bytes().await.map_err(|e| e.to_string())?; - let part_path = tmp_dir.join(part); - fs::write(&part_path, &bytes).map_err(|e| e.to_string())?; - *done += 1; - let _ = app.emit("workshop-progress", DownloadProgress { - instance_id: package_id.to_string(), - percent: (*done as f64 / total.max(1) as f64) * 100.0, - }); - downloaded.push(part_path); - } - - if downloaded.len() == 1 { - return Ok(downloaded.remove(0)); - } - - let combined_dir = tmp_dir.join("_combined"); - fs::create_dir_all(&combined_dir).map_err(|e| e.to_string())?; - let combined = combined_dir.join(parts[0].clone()); - let mut out = std::io::BufWriter::new(fs::File::create(&combined).map_err(|e| e.to_string())?); - for path in &downloaded { - let mut f = std::io::BufReader::new(fs::File::open(path).map_err(|e| e.to_string())?); - std::io::copy(&mut f, &mut out).map_err(|e| e.to_string())?; - } - out.flush().map_err(|e| e.to_string())?; - Ok(combined) -} - -fn list_archive(zip_tmp: &Path) -> Result, String> { - let zip_str = zip_tmp.to_str().unwrap_or(""); - if cfg!(target_os = "linux") { - if let Ok(out) = std::process::Command::new("bsdtar") - .args(["-tf", zip_str]) - .output() - { - if out.status.success() { - let listing = String::from_utf8_lossy(&out.stdout); - return Ok(listing.lines() - .map(|l| l.trim().to_string()) - .filter(|l| !l.is_empty() && !l.ends_with('/')) - .collect()); - } - } - let unzip_list = std::process::Command::new("unzip") - .args(["-l", zip_str]) - .output() - .map_err(|e| e.to_string())?; - if !unzip_list.status.success() { - return Err(format!("Failed to list contents of {}", zip_str)); - } - let listing = String::from_utf8_lossy(&unzip_list.stdout); - Ok(listing.lines() - .filter_map(|l| { - let mut parts = l.trim().split_whitespace(); - let size_str = parts.next()?; - size_str.parse::().ok()?; - parts.next()?; - parts.next()?; - Some(parts.collect::>().join(" ")) - }) - .filter(|l| !l.ends_with('/') && !l.contains('*')) - .collect()) - } else if cfg!(target_os = "android") { - let unzip_list = std::process::Command::new("unzip") - .args(["-l", zip_str]) - .output() - .map_err(|e| e.to_string())?; - if !unzip_list.status.success() { - return Err(format!("Failed to list contents of {}", zip_str)); - } - let listing = String::from_utf8_lossy(&unzip_list.stdout); - Ok(listing.lines() - .filter_map(|l| { - let mut parts = l.trim().split_whitespace(); - let size_str = parts.next()?; - size_str.parse::().ok()?; - parts.next()?; - parts.next()?; - Some(parts.collect::>().join(" ")) - }) - .filter(|l| !l.ends_with('/') && !l.contains('*')) - .collect()) - } else { - let listing = std::process::Command::new("tar") - .args(["-tf", zip_str]) - .output() - .map_err(|e| e.to_string())?; - let listing_str = String::from_utf8_lossy(&listing.stdout); - Ok(listing_str.lines() - .map(|l| l.trim().to_string()) - .filter(|l| !l.is_empty() && !l.ends_with('/')) - .collect()) - } -} - -fn extract_archive(zip_tmp: &Path, dest_dir: &Path) -> Result { - let zip_str = zip_tmp.to_str().unwrap_or(""); - if cfg!(target_os = "linux") { - let mut extract_ok = false; - if let Ok(out) = std::process::Command::new("bsdtar") - .args(["-tf", zip_str]) - .output() - { - if out.status.success() { - let st = std::process::Command::new("bsdtar") - .args(["-xf", zip_str, "-C", dest_dir.to_str().unwrap()]) - .status() - .map_err(|e| e.to_string())?; - extract_ok = st.success(); - } - } - if !extract_ok { - let st = std::process::Command::new("unzip") - .args(["-o", zip_str, "-d", dest_dir.to_str().unwrap()]) - .status() - .map_err(|e| e.to_string())?; - extract_ok = st.success(); - } - Ok(extract_ok) - } else if cfg!(target_os = "android") { - let st = std::process::Command::new("unzip") - .args(["-o", zip_str, "-d", dest_dir.to_str().unwrap()]) - .status() - .map_err(|e| e.to_string())?; - Ok(st.success()) - } else { - let st = std::process::Command::new("tar") - .args(["-xf", zip_str, "-C", dest_dir.to_str().unwrap()]) - .status() - .map_err(|e| e.to_string())?; - Ok(st.success()) - } -} - -#[tauri::command] -pub async fn workshop_install(app: AppHandle, request: WorkshopInstallRequest) -> Result<(), String> { - let instance_dir = util::get_instance_working_dir(&app, &request.instance_id); - if !instance_dir.exists() { - return Err("Instance not installed".into()); - } - let root = util::get_app_dir(&app); - let media_dir = instance_dir.join("Windows64Media"); - let dlc_dir = media_dir.join("DLC"); - let game_hdd = instance_dir.join("Windows64").join("GameHDD"); - let mob_dir = instance_dir.join("Common").join("res").join("mob"); - let wf_path = instance_dir.join("workshop_files.json"); - let wp_path = instance_dir.join("workshop_packages.json"); - let mut workshop_files: Vec = fs::read_to_string(&wf_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - - let mut workshop_packages: Vec = fs::read_to_string(&wp_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - - workshop_packages.retain(|p| p.id != request.package_id); - let raw_base = format!("https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main/{}", request.package_id); - let tmp_dir = root.join(format!("workshop_tmp_{}", request.package_id)); - let _ = fs::remove_dir_all(&tmp_dir); - fs::create_dir_all(&tmp_dir).map_err(|e| e.to_string())?; - let mut pkg_dirs: Vec = Vec::new(); - let total_parts = request.zips.len(); - let mut done_parts = 0usize; - for (parts, placeholder) in group_archives(&request.zips) { - let dest_dir = if placeholder.is_empty() { - instance_dir.clone() - } else { - instance_dir.clone().join(placeholder - .replace("{MediaDir}", media_dir.to_str().unwrap_or("")) - .replace("{DLCDir}", dlc_dir.to_str().unwrap_or("")) - .replace("{GameHDD}", game_hdd.to_str().unwrap_or("")) - .replace("{MobDir}", mob_dir.to_str().unwrap_or(""))) - }; - - fs::create_dir_all(&dest_dir).map_err(|e| e.to_string())?; - let archive_tmp = download_and_assemble(&app, &tmp_dir, &parts, &raw_base, &request.package_id, &mut done_parts, total_parts).await?; - let files = list_archive(&archive_tmp)?; - for f in &files { - let full = dest_dir.join(f); - if full.is_file() { - let bak = format!("{}.bak", full.to_string_lossy()); - if !Path::new(&bak).exists() { - let _ = fs::rename(&full, &bak); - } - } - } - let extract_ok = extract_archive(&archive_tmp, &dest_dir)?; - if !extract_ok { - let _ = fs::remove_dir_all(&tmp_dir); - return Err(format!("Extraction failed for {}", parts[0])); - } - let extracted_files: Vec = files.iter() - .map(|f| dest_dir.join(f).to_string_lossy().to_string()) - .collect(); - - for f in &extracted_files { - if !workshop_files.contains(f) { - workshop_files.push(f.clone()); - } - if !pkg_dirs.contains(f) { - pkg_dirs.push(f.clone()); - } - } - } - - let _ = fs::remove_dir_all(&tmp_dir); - - if let Ok(json) = serde_json::to_string(&workshop_files) { - let _ = fs::write(&wf_path, json); - } - - workshop_packages.push(InstalledWorkshopPackage { - id: request.package_id.clone(), - version: request.version.clone(), - dirs: pkg_dirs, - }); - if let Ok(json) = serde_json::to_string(&workshop_packages) { - let _ = fs::write(&wp_path, json); - } - - Ok(()) -} - -#[tauri::command] -pub async fn workshop_uninstall(app: AppHandle, instance_id: String, package_id: String) -> Result<(), String> { - let instance_dir = util::get_instance_working_dir(&app, &instance_id); - let wp_path = instance_dir.join("workshop_packages.json"); - let wf_path = instance_dir.join("workshop_files.json"); - let mut packages: Vec = fs::read_to_string(&wp_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - - if let Some(pkg) = packages.iter().find(|p| p.id == package_id) { - for file in &pkg.dirs { - let path = PathBuf::from(file); - if path.is_file() { - let _ = fs::remove_file(&path); - } - let bak = format!("{}.bak", path.to_string_lossy()); - if Path::new(&bak).is_file() { - let _ = fs::rename(&bak, &path); - } - } - } - - let removed_dirs: std::collections::HashSet = packages - .iter() - .find(|p| p.id == package_id) - .map(|p| p.dirs.iter().cloned().collect()) - .unwrap_or_default(); - - packages.retain(|p| p.id != package_id); - if let Ok(json) = serde_json::to_string(&packages) { - let _ = fs::write(&wp_path, json); - } - - let mut workshop_files: Vec = fs::read_to_string(&wf_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - workshop_files.retain(|f| !removed_dirs.contains(f)); - if let Ok(json) = serde_json::to_string(&workshop_files) { - let _ = fs::write(&wf_path, json); - } - - Ok(()) -} - -#[tauri::command] -pub fn workshop_list_installed(app: AppHandle) -> Vec { - let root = util::get_app_dir(&app); - let mut result = Vec::new(); - let mut instance_dirs = vec![root.join("instances")]; - let config_val = config::load_config_raw(app.clone()); - if let Some(editions) = config_val.custom_editions { - for ed in editions { - if let Some(path) = ed.path { - instance_dirs.push(PathBuf::from(path)); - } - } - } - - for base_dir in instance_dirs { - if base_dir.ends_with("instances") { - if let Ok(entries) = fs::read_dir(&base_dir) { - for entry in entries.flatten() { - if !entry.path().is_dir() { continue; } - let instance_id = entry.file_name().to_string_lossy().to_string(); - let wp_path = entry.path().join("workshop_packages.json"); - let packages: Vec = fs::read_to_string(&wp_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - for pkg in packages { - result.push(InstalledPackageEntry { - instance_id: instance_id.clone(), - package_id: pkg.id, - version: pkg.version, - }); - } - } - } - } else { - let instance_id = base_dir.file_name().and_then(|n| n.to_str()).unwrap_or("custom").to_string(); - let config_val = config::load_config_raw(app.clone()); - let final_id = config_val.custom_editions.as_ref() - .and_then(|eds| eds.iter().find(|e| e.path.as_deref() == base_dir.to_str()).map(|e| e.id.clone())) - .unwrap_or(instance_id); - - let wp_path = base_dir.join("workshop_packages.json"); - let packages: Vec = fs::read_to_string(&wp_path) - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default(); - for pkg in packages { - result.push(InstalledPackageEntry { - instance_id: final_id.clone(), - package_id: pkg.id, - version: pkg.version, - }); - } - } - } - result -} diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs deleted file mode 100644 index b6e30d0..0000000 --- a/src-tauri/src/config.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::fs; -use tauri::AppHandle; -use crate::types::AppConfig; -use crate::util; -pub fn load_config_raw(app: AppHandle) -> AppConfig { - let path = util::get_config_path(&app); - if let Ok(content) = fs::read_to_string(path) { - if let Ok(config) = serde_json::from_str(&content) { - return config; - } - } - - let old_path = util::get_app_dir(&app).join("emerald_legacy_config.txt"); - let username = fs::read_to_string(old_path).unwrap_or_else(|_| "Player".into()); - AppConfig { - username, - linux_runner: None, - skin_base64: None, - skin_library: None, - theme_style_id: None, - theme_palette_id: None, - apple_silicon_performance_boost: None, - custom_editions: None, - customizations: None, - custom_paths: None, - profile: Some("legacy_evolved".into()), - animations_enabled: Some(true), - vfx_enabled: Some(true), - rpc_enabled: Some(true), - start_fullscreen: Some(false), - music_vol: Some(50), - sfx_vol: Some(100), - legacy_mode: Some(false), - skip_intro: Some(false), - mangohud_enabled: None, - saved_servers: None, - extra_launch_args: None, - launch_prefix: None, - launch_env_vars: None, - instance_launch_args: None, - android_runner: None, - android_audio_backend: None, - goldmapper_enabled: Some(true), - goldmapper_mappings: None, - http_proxy: None, - } -} - -pub fn save_config_raw(app: &AppHandle, config: &AppConfig) { - let path = util::get_config_path(app); - let _ = fs::create_dir_all(path.parent().unwrap()); - if let Ok(json) = serde_json::to_string(config) { - let _ = fs::write(path, json); - } -} diff --git a/src-tauri/src/lce_auth.rs b/src-tauri/src/lce_auth.rs deleted file mode 100644 index bc23995..0000000 --- a/src-tauri/src/lce_auth.rs +++ /dev/null @@ -1,35 +0,0 @@ -use tauri::plugin::{Builder, PluginHandle, TauriPlugin}; -use tauri::Wry; -pub struct LceAuthState(pub PluginHandle); -pub fn init() -> TauriPlugin { - Builder::new("emerald-lce-auth") - .setup(|app, api| { - #[cfg(target_os = "android")] - { - use tauri::Manager; - let handle = api.register_android_plugin("com.emerald.legacy", "LceAuthPlugin")?; - app.manage(LceAuthState(handle)); - } - Ok(()) - }) - .build() -} - -#[tauri::command] -pub async fn start_lce_auth(app: tauri::AppHandle) -> Result { - #[cfg(target_os = "android")] - { - use tauri::Manager; - let state = app.state::(); - state - .0 - .run_mobile_plugin_async("startAuth", ()) - .await - .map_err(|e| e.to_string()) - } - #[cfg(not(target_os = "android"))] - { - let _ = app; - Err("LCE Online auth is only supported on Android".into()) //neo: erm, rust-side only. its supported on desktop on the typescript side. - } -} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs deleted file mode 100644 index 6b760be..0000000 --- a/src-tauri/src/lib.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![cfg_attr(target_os = "android", allow(dead_code, unused))] -mod types; -mod state; -mod config; -mod util; -mod playtime; -mod platform; -mod networking; -mod workshop_server; -mod lce_auth; -#[cfg(target_os = "android")] -mod android_runtime; -mod commands; -use std::collections::HashMap; -use std::sync::Arc; -use std::sync::atomic::AtomicBool; -use tokio::sync::Mutex; -use tauri::{Emitter, Manager}; -use commands::config as config_cmds; -use commands::dlc; -use commands::download; -use commands::file_dialogs; -use commands::game; -use commands::goldmapper; -use commands::macos_setup; -use commands::platform as platform_cmd; -use commands::plugins; -use commands::proxy_cmd; -use commands::runners; -use commands::skin; -use commands::steam; -use commands::workshop; -use networking::relay; -use networking::stun; -use state::{DownloadState, GameState, ProxyGuard}; -fn webview_deep_link_interceptor() -> impl tauri::plugin::Plugin { tauri::plugin::Builder::::new("emerald-deep-link-interceptor").on_navigation(|webview, url| { if url.scheme() == "emerald" || url.scheme() == "emeraldlauncher" { let _ = webview.app_handle().emit("deep-link", vec![url.to_string()]); false } else { true }}).build()} -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - let mut builder = tauri::Builder::default() - .plugin(tauri_plugin_deep_link::init()) - .plugin(webview_deep_link_interceptor()) - .plugin(lce_auth::init()) - .plugin(tauri_plugin_process::init()) - .plugin(tauri_plugin_gamepad::init()) - .plugin(tauri_plugin_opener::init()); - #[cfg(desktop)] - { - builder = builder - .plugin(tauri_plugin_single_instance::init(|app, args, _cwd| { - let urls: Vec = args - .iter() - .filter(|a| { - a.starts_with("emerald://") - || a.starts_with("emeraldlauncher://") - || a.starts_with("discord-1482504445152460871://") - }) - .cloned() - .collect(); - if !urls.is_empty() { - let _ = app.emit("deep-link", urls); - } - })) - .plugin(tauri_plugin_updater::Builder::new().build()) - .plugin(tauri_plugin_drpc::init()); - } - builder - .manage(DownloadState { - tokens: Arc::new(Mutex::new(HashMap::new())), - }) - .manage(GameState { - child: Arc::new(Mutex::new(None)), - workshop_cancel: Arc::new(Mutex::new(None)), - manual_stop: Arc::new(AtomicBool::new(false)), - }) - .manage(ProxyGuard { - cancel_tokens: Arc::new(Mutex::new(HashMap::new())), - local_port: Arc::new(Mutex::new(None)), - }) - .invoke_handler(tauri::generate_handler![ - platform_cmd::get_platform, - macos_setup::setup_macos_runtime, - dlc::list_git_directory, - dlc::download_dlc_files, - game::launch_game, - game::stop_game, - game::check_game_installed, - config_cmds::save_config, - config_cmds::load_config, - download::download_and_install, - game::open_instance_folder, - game::open_container_settings, - download::cancel_download, - runners::get_available_runners, - config_cmds::get_external_palettes, - #[cfg(desktop)] - config_cmds::import_theme, - #[cfg(desktop)] - config_cmds::export_settings, - #[cfg(desktop)] - config_cmds::import_settings, - #[cfg(desktop)] - file_dialogs::pick_folder, - download::download_runner, - game::delete_instance, - game::sync_dlc, - skin::fetch_skin, - workshop::workshop_install, - workshop::workshop_uninstall, - workshop::workshop_list_installed, - skin::get_screenshots, - skin::delete_screenshot, - skin::open_screenshot_folder, - skin::save_global_skin_pck, - download::check_game_update, - macos_setup::check_macos_runtime_installed, - macos_setup::check_macos_runtime_installed_fast, - skin::download_logo, - #[cfg(desktop)] - file_dialogs::pick_file, - #[cfg(desktop)] - file_dialogs::save_file_dialog, - file_dialogs::write_binary_file, - file_dialogs::read_binary_file, - skin::read_screenshot_as_data_url, - steam::add_to_steam, - proxy_cmd::http_proxy_request, - game::get_instance_path, - game::get_playtime, - game::get_playtime_daily, - game::get_instance_args_schema, - #[cfg(desktop)] - game::backup_instance, - #[cfg(desktop)] - game::restore_instance, - commands::console2lce::import_world, - commands::console2lce::import_lce_save, - commands::java2lce::java_to_lce, - commands::java2lce::lce_to_java, - stun::stun_discover, - relay::start_relay_proxy, - relay::start_host_relay, - relay::stop_proxy, - relay::stop_all_proxies, - relay::join_game, - lce_auth::start_lce_auth, - plugins::get_plugins_dir, - plugins::list_directory, - plugins::create_plugin_dir, - plugins::remove_plugin_dir, - game::switch_proton, - game::install_latest_driver, - game::set_audio_backend, - goldmapper::goldmapper_get_defaults, - goldmapper::goldmapper_load_config, - goldmapper::goldmapper_save_config, - goldmapper::goldmapper_reset_config, - ]) - .setup(|app| { - let app_handle = app.handle().clone(); - #[cfg(desktop)] - { - let config = config::load_config_raw(app_handle.clone()); - if config.start_fullscreen.unwrap_or(false) { - if let Some(window) = app_handle.get_webview_window("main") { - let _ = window.set_fullscreen(true); - } - } - } - - #[cfg(target_os = "android")] - { - let handle = app_handle.clone(); - if let Some(window) = app_handle.get_webview_window("main") { - window.on_window_event(move |event| { - if let tauri::WindowEvent::Focused(true) = event { - playtime::finish_active_session(&handle); - } - }); - } - } - - #[cfg(desktop)] - { - let args: Vec = std::env::args().collect(); - if args.len() > 1 && !args[1].starts_with('-') { - let first = &args[1]; - let is_deep_link = first.starts_with("emerald://") - || first.starts_with("emeraldlauncher://") - || first.starts_with("discord-1482504445152460871://"); - if !is_deep_link { - let instance_id = first.clone(); - let app_handle_clone = app.handle().clone(); - tauri::async_runtime::spawn(async move { - if let Some(window) = app_handle_clone.get_webview_window("main") { - let _ = window.hide(); - } - let state = app_handle_clone.state::(); - match game::launch_game(app_handle_clone.clone(), state, instance_id, Vec::new(), vec![]).await { - Ok(_) => app_handle_clone.exit(0), - Err(e) => { - let _ = app_handle_clone.emit("backend-error", format!("Auto-launch: {e}")); - eprintln!("Auto-launch error: {}", e); - app_handle_clone.exit(1); - } - } - }); - } - } - } - Ok(()) - }) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs deleted file mode 100644 index 753f13a..0000000 --- a/src-tauri/src/main.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -fn main() { - #[cfg(target_os = "linux")] - { - use std::env; - use std::process::{Command, Stdio, exit}; - use std::io::{BufReader, BufRead}; - use std::thread; - let stage = env::var("EMERALD_LAUNCH_STAGE").unwrap_or_else(|_| "0".to_string()); - if stage == "0" { - let mut cmd = Command::new(env::current_exe().unwrap()); - cmd.args(env::args().skip(1)); - cmd.env("EMERALD_LAUNCH_STAGE", "1"); - - let wayland_libs = ["/usr/lib64/libwayland-client.so.0", "/usr/lib/libwayland-client.so.0"]; - if let Some(path) = wayland_libs.iter().find(|p| std::path::Path::new(p).exists()) { - cmd.env("LD_PRELOAD", path); - } - - let mut child = cmd - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("failed to spawn child process"); - - let stdout = child.stdout.take().expect("failed to take stdout"); - let stderr = child.stderr.take().expect("failed to take stderr"); - let child_id = child.id(); - fn check_line(l: &str) -> bool { - let low = l.to_lowercase(); - (low.contains("gbm") && low.contains("buffer")) || - (low.contains("dmabuf") && low.contains("renderer")) || - (low.contains("invalid argument") && low.contains("buffer")) || - (low.contains("wayland") && low.contains("protocol error")) - } - - let h1 = thread::spawn(move || { - let reader = BufReader::new(stdout); - for line in reader.lines() { - if let Ok(l) = line { - println!("{}", l); - if check_line(&l) { - eprintln!("!!! Emerald: Graphics error detected in stdout: {}", l); - #[cfg(unix)] - let _ = Command::new("kill").arg("-9").arg(child_id.to_string()).status(); - return true; - } - } - } - false - }); - - let h2 = thread::spawn(move || { - let reader = BufReader::new(stderr); - for line in reader.lines() { - if let Ok(l) = line { - eprintln!("{}", l); - if check_line(&l) { - eprintln!("!!! Emerald: Graphics error detected in stderr: {}", l); - #[cfg(unix)] - let _ = Command::new("kill").arg("-9").arg(child_id.to_string()).status(); - return true; - } - } - } - false - }); - - let status = child.wait().expect("failed to wait on child process"); - - let found_error = h1.join().unwrap_or(false) || h2.join().unwrap_or(false); - - if found_error || !status.success() { - if found_error { - println!("Emerald: Automatic recovery triggered for graphics crash/invisible launch."); - } - let mut retry_cmd = Command::new(env::current_exe().unwrap()); - retry_cmd.args(env::args().skip(1)); - retry_cmd.env("EMERALD_LAUNCH_STAGE", "2") - .env("GDK_BACKEND", "x11") - .env("WEBKIT_DISABLE_DMABUF_RENDERER", "1") - .env("WEBKIT_DISABLE_COMPOSITING_MODE", "1"); - - if let Some(path) = wayland_libs.iter().find(|p| std::path::Path::new(p).exists()) { - retry_cmd.env("LD_PRELOAD", path); - } - - let mut retry_child = retry_cmd.spawn().expect("failed to spawn fallback child process"); - - let retry_status = retry_child.wait().expect("failed to wait on fallback child process"); - exit(retry_status.code().unwrap_or(1)); - } - exit(0); - } - } - - emerald_lib::run() -} diff --git a/src-tauri/src/networking/mod.rs b/src-tauri/src/networking/mod.rs deleted file mode 100644 index 6261c84..0000000 --- a/src-tauri/src/networking/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod stun; -pub mod relay; diff --git a/src-tauri/src/networking/relay.rs b/src-tauri/src/networking/relay.rs deleted file mode 100644 index 0f308c8..0000000 --- a/src-tauri/src/networking/relay.rs +++ /dev/null @@ -1,214 +0,0 @@ -use tauri::State; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::{TcpListener, TcpStream}; -use tokio_util::sync::CancellationToken; -use crate::state::ProxyGuard; -const PROXY_ADDR: &str = "proxy.mclegacyedition.xyz:2052"; //neo: yeah bro im hardcoding it -async fn read_line(stream: &mut TcpStream) -> Result { - let mut buf = Vec::new(); - let mut byte = [0u8; 1]; - loop { - stream.read_exact(&mut byte).await.map_err(|e| e.to_string())?; - if byte[0] == b'\n' { break; } - if byte[0] != b'\r' { buf.push(byte[0]); } - } - String::from_utf8(buf).map_err(|e| e.to_string()) -} - -async fn write_line(stream: &mut TcpStream, line: &str) -> Result<(), String> { - let data = format!("{}\n", line); - stream.write_all(data.as_bytes()).await.map_err(|e| e.to_string()) -} - -async fn run_host_relay( - _proxy_state: &ProxyGuard, - proxy_addr: &str, - auth_token: &str, - game_port: u16, - cancel: CancellationToken, -) -> Result<(), String> { - let mut host_conn = TcpStream::connect(proxy_addr) - .await - .map_err(|e| format!("Proxy connect failed: {}", e))?; - - write_line(&mut host_conn, &format!("HOST {} 0", auth_token)).await?; - let mut game_stream = tokio::time::timeout( - std::time::Duration::from_secs(30), - async { - loop { - match TcpStream::connect(format!("127.0.0.1:{}", game_port)).await { - Ok(s) => return Ok::<_, String>(s), - Err(_) => { - tokio::select! { - _ = cancel.cancelled() => return Err("Cancelled".into()), - _ = tokio::time::sleep(std::time::Duration::from_secs(1)) => {} - } - } - } - } - } - ).await - .map_err(|_| "Timed out waiting for game to start".to_string())??; - let client_line = read_line(&mut host_conn).await?; - let client_parts: Vec<&str> = client_line.split_whitespace().collect(); - if client_parts.len() < 2 || client_parts[0] != "CLIENT" { - return Err(format!("Expected CLIENT, got: {}", client_line)); - } - let joiner_id = client_parts[1]; - let mut accept_conn = TcpStream::connect(proxy_addr) - .await - .map_err(|e| format!("Proxy connect failed: {}", e))?; - write_line(&mut accept_conn, &format!("ACCEPT {} 0 {}", auth_token, joiner_id)).await?; - tokio::select! { - res = tokio::io::copy_bidirectional(&mut game_stream, &mut accept_conn) => { - if let Err(e) = res { - eprintln!("Host Relay error: {}", e); - } - }, - _ = cancel.cancelled() => {}, - } - - Ok(()) -} - -async fn run_relay_proxy( - proxy_state: &ProxyGuard, - proxy_addr: &str, - auth_token: &str, - target_session: &str, - cancel: CancellationToken, -) -> Result { - let mut stream = TcpStream::connect(proxy_addr) - .await - .map_err(|e| format!("Proxy connect failed: {}", e))?; - - write_line(&mut stream, &format!("JOIN {} 0 {}", auth_token, target_session)).await?; - let listener = TcpListener::bind("0.0.0.0:61000") - .await - .map_err(|e| format!("Bind failed: {}", e))?; - let local_port = listener.local_addr().map_err(|e| e.to_string())?.port(); - { - let mut port = proxy_state.local_port.lock().await; - *port = Some(local_port); - } - - let (mut local_stream, _) = tokio::select! { - r = listener.accept() => r.map_err(|e| format!("Accept failed: {}", e))?, - _ = cancel.cancelled() => return Err("Cancelled".into()), - }; - - tokio::select! { - res = tokio::io::copy_bidirectional(&mut local_stream, &mut stream) => { - if let Err(e) = res { - eprintln!("Relay Proxy error: {}", e); - } - }, - _ = cancel.cancelled() => {}, - } - - Ok(local_port) -} - -#[tauri::command] -pub async fn start_host_relay( - proxy_state: State<'_, ProxyGuard>, - auth_token: String, - game_port: u16, -) -> Result<(), String> { - let addr = PROXY_ADDR; - let cancel = CancellationToken::new(); - let session_id = "__host__".to_string(); - { - let mut tokens = proxy_state.cancel_tokens.lock().await; - if let Some(old) = tokens.insert(session_id.clone(), cancel.clone()) { - old.cancel(); - } - } - - let result = run_host_relay(&proxy_state, &addr, &auth_token, game_port, cancel).await; - { - let mut tokens = proxy_state.cancel_tokens.lock().await; - tokens.remove(&session_id); - } - - result -} - -#[tauri::command] -pub async fn start_relay_proxy( - proxy_state: State<'_, ProxyGuard>, - auth_token: String, - target_session: String, -) -> Result { - let addr = PROXY_ADDR; - let cancel = CancellationToken::new(); - let session_id = target_session.clone(); - { - let mut tokens = proxy_state.cancel_tokens.lock().await; - tokens.insert(session_id.clone(), cancel.clone()); - } - - let local_port = run_relay_proxy(&proxy_state, &addr, &auth_token, &target_session, cancel).await?; - { - let mut tokens = proxy_state.cancel_tokens.lock().await; - tokens.remove(&session_id); - } - - Ok(local_port) -} - -#[tauri::command] -pub async fn stop_proxy(proxy_state: State<'_, ProxyGuard>, session_id: String) -> Result<(), String> { - let mut tokens = proxy_state.cancel_tokens.lock().await; - let found = tokens.remove(&session_id); - if let Some(token) = found { - token.cancel(); - let mut port = proxy_state.local_port.lock().await; - *port = None; - } - Ok(()) -} - -#[tauri::command] -pub async fn stop_all_proxies(proxy_state: State<'_, ProxyGuard>) -> Result<(), String> { - let mut tokens = proxy_state.cancel_tokens.lock().await; - for (_, token) in tokens.drain() { - token.cancel(); - } - let mut port = proxy_state.local_port.lock().await; - *port = None; - Ok(()) -} - -#[tauri::command] -pub async fn join_game( - app: tauri::AppHandle, - game_state: State<'_, crate::state::GameState>, - _proxy_state: State<'_, ProxyGuard>, - _api_base_url: String, - _auth_token: String, - host_ip: String, - host_port: u16, - _target_session: String, - instance_id: String, -) -> Result<(), String> { - let server = crate::types::McServer { - name: host_ip.clone(), - ip: host_ip, - port: host_port, - }; - #[cfg(target_os = "windows")] - { - let deadline = tokio::time::Instant::now() + tokio::time::Duration::from_secs(10); - loop { - if tokio::net::TcpStream::connect(format!("127.0.0.1:{}", host_port)).await.is_ok() { - break; - } - if tokio::time::Instant::now() >= deadline { - return Err("Timed out waiting for relay proxy".into()); - } - tokio::time::sleep(std::time::Duration::from_millis(200)).await; - } - } //neo: workaround for Windows having a race condition where the game is launched before the relay proxy - crate::commands::game::launch_game(app, game_state, instance_id, vec![server], vec![]).await -} diff --git a/src-tauri/src/networking/stun.rs b/src-tauri/src/networking/stun.rs deleted file mode 100644 index c78d59a..0000000 --- a/src-tauri/src/networking/stun.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::types::P2pEndpoint; -async fn stun_discover_impl() -> Result { - let socket = tokio::net::UdpSocket::bind("0.0.0.0:0").await.map_err(|e| e.to_string())?; - let stun_addr = tokio::net::lookup_host("stun.l.google.com:19302").await - .map_err(|e| format!("STUN DNS lookup failed: {}", e))? - .next() - .ok_or_else(|| "STUN DNS returned no addresses".to_string())?; - - let magic_cookie: u32 = 0x2112A442; - let mut trans_id = [0u8; 12]; - rand::Rng::fill(&mut rand::thread_rng(), &mut trans_id); - let mut req = Vec::with_capacity(20); - req.extend_from_slice(&0x0001u16.to_be_bytes()); - req.extend_from_slice(&0x0000u16.to_be_bytes()); - req.extend_from_slice(&magic_cookie.to_be_bytes()); - req.extend_from_slice(&trans_id); - socket.send_to(&req, stun_addr).await.map_err(|e| format!("STUN send: {}", e))?; - let mut buf = [0u8; 512]; - tokio::time::timeout( - std::time::Duration::from_secs(5), - socket.recv_from(&mut buf) - ).await.map_err(|_| "STUN request timed out (5s)".to_string())? - .map_err(|e| format!("STUN recv: {}", e))?; - let msg_type = u16::from_be_bytes([buf[0], buf[1]]); - let rcvd_cookie = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]); - if msg_type != 0x0101 || rcvd_cookie != magic_cookie { - return Err(format!("Invalid STUN response (type=0x{:04X}, cookie=0x{:08X})", msg_type, rcvd_cookie)); - } - - let mut pos = 20; - while pos + 4 <= buf.len() { - let attr_type = u16::from_be_bytes([buf[pos], buf[pos+1]]); - let attr_len = u16::from_be_bytes([buf[pos+2], buf[pos+3]]) as usize; - pos += 4; - if attr_type == 0x0020 && attr_len >= 8 && pos + 8 <= buf.len() { - let _family = buf[pos+1]; - let xport = u16::from_be_bytes([buf[pos+2], buf[pos+3]]); - let port = xport ^ (magic_cookie >> 16) as u16; - let ip_bytes = [ - buf[pos+4] ^ (magic_cookie >> 24) as u8, - buf[pos+5] ^ (magic_cookie >> 16) as u8, - buf[pos+6] ^ (magic_cookie >> 8) as u8, - buf[pos+7] ^ magic_cookie as u8, - ]; - return Ok(P2pEndpoint { - ip: format!("{}.{}.{}.{}", ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]), - port, - }); - } - pos += attr_len; - } - - Err("No XOR-MAPPED-ADDRESS in STUN response".into()) -} - -#[tauri::command] -pub async fn stun_discover() -> Result { - stun_discover_impl().await -} diff --git a/src-tauri/src/platform/linux.rs b/src-tauri/src/platform/linux.rs deleted file mode 100644 index e803d41..0000000 --- a/src-tauri/src/platform/linux.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::fs; -use crate::util; -pub fn kill_process_tree(app: &tauri::AppHandle, instance_id: &str) { - let root = util::get_app_dir(app); - let instance_dir = root.join("instances").join(instance_id); - let target = util::unix_path_to_wine_z_path(&instance_dir.join("Minecraft.Client.exe")); - let Ok(entries) = fs::read_dir("/proc") else { return }; - for entry in entries.flatten() { - let Ok(pid) = entry.file_name().to_string_lossy().parse::() else { continue }; - let cmdline = fs::read_to_string(format!("/proc/{}/cmdline", pid)) - .unwrap_or_default(); - if cmdline.contains(&*target) { - unsafe { libc::kill(pid as i32, libc::SIGKILL); } - } - } -} diff --git a/src-tauri/src/platform/macos.rs b/src-tauri/src/platform/macos.rs deleted file mode 100644 index c97ab93..0000000 --- a/src-tauri/src/platform/macos.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use tauri::{AppHandle, Emitter, Manager}; -use crate::types::MacosSetupProgressPayload; -pub fn get_macos_runtime_dir(app: &AppHandle) -> PathBuf { - let home = app - .path() - .home_dir() - .ok() - .or_else(|| std::env::var("HOME").ok().map(PathBuf::from)) - .unwrap_or_else(|| PathBuf::from("/")); - home.join("Library") - .join("Application Support") - .join("com.emerald.legacy") - .join("runtime") -} - -pub fn find_executable_recursive(root: &PathBuf, file_name: &str) -> Option { - let entries = fs::read_dir(root).ok()?; - for entry in entries.flatten() { - let path = entry.path(); - if let Some(name) = path.file_name().and_then(|n| n.to_str()) { - if name == file_name { - return Some(path); - } - } - if path.is_dir() { - if let Some(found) = find_executable_recursive(&path, file_name) { - return Some(found); - } - } - } - None -} - -pub fn emit_macos_setup_progress(window: &tauri::Window, stage: &str, message: String, percent: Option) { - let _ = window.emit( - "macos-setup-progress", - MacosSetupProgressPayload { - stage: stage.to_string(), - message, - percent, - }, - ); -} - -pub fn is_macos_runtime_installed(app: &AppHandle) -> bool { - let runtime_dir = get_macos_runtime_dir(app); - let toolkit_dir = runtime_dir.join("toolkit"); - if !toolkit_dir.exists() { - return false; - } - if find_executable_recursive(&toolkit_dir, "Game Porting Toolkit.app").is_some() { - return true; - } - find_executable_recursive(&toolkit_dir, "wine").is_some() - || find_executable_recursive(&toolkit_dir, "wine64").is_some() -} diff --git a/src-tauri/src/platform/mod.rs b/src-tauri/src/platform/mod.rs deleted file mode 100644 index 6bbf20a..0000000 --- a/src-tauri/src/platform/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[cfg(unix)] -pub mod linux; -#[cfg(target_os = "macos")] -pub mod macos; -#[cfg(target_os = "windows")] -pub mod windows; diff --git a/src-tauri/src/platform/windows.rs b/src-tauri/src/platform/windows.rs deleted file mode 100644 index f86849c..0000000 --- a/src-tauri/src/platform/windows.rs +++ /dev/null @@ -1 +0,0 @@ -//neo: windows sucks ass btw diff --git a/src-tauri/src/playtime.rs b/src-tauri/src/playtime.rs deleted file mode 100644 index 957b09a..0000000 --- a/src-tauri/src/playtime.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::collections::HashMap; -use std::path::PathBuf; -use std::time::{SystemTime, UNIX_EPOCH}; -use tauri::AppHandle; -use serde::{Serialize, Deserialize}; -use crate::util; -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct PlaytimeSession { - pub start: u64, - pub end: u64, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct PlaytimeData { - pub sessions: HashMap>, -} - -#[derive(Serialize, Deserialize)] -struct ActiveSession { - instance_id: String, - start: u64, -} - -#[derive(Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct PlaytimeResponse { - pub total_seconds: u64, - pub week_seconds: u64, - pub day_seconds: u64, -} - -fn playtime_path(app: &AppHandle) -> PathBuf { - util::get_app_dir(app).join("playtime.json") -} - -pub fn load(app: &AppHandle) -> PlaytimeData { - let path = playtime_path(app); - if path.exists() { - let content = std::fs::read_to_string(&path).unwrap_or_default(); - serde_json::from_str(&content).unwrap_or(PlaytimeData { sessions: HashMap::new() }) - } else { - PlaytimeData { sessions: HashMap::new() } - } -} - -pub fn save(app: &AppHandle, data: &PlaytimeData) { - let path = playtime_path(app); - if let Some(parent) = path.parent() { - let _ = std::fs::create_dir_all(parent); - } - if let Ok(content) = serde_json::to_string_pretty(data) { - let _ = std::fs::write(&path, content); - } -} - -pub fn record_session(app: &AppHandle, instance_id: &str, start: u64, end: u64) { - let mut data = load(app); - let sessions = data.sessions.entry(instance_id.to_string()).or_default(); - sessions.push(PlaytimeSession { start, end }); - save(app, &data); -} - -const MAX_SESSION_SECONDS: u64 = 12 * 60 * 60; -fn active_session_path(app: &AppHandle) -> PathBuf { - util::get_app_dir(app).join("active_session.json") -} - -pub fn start_session(app: &AppHandle, instance_id: &str) { - let start = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let active = ActiveSession { instance_id: instance_id.to_string(), start }; - let path = active_session_path(app); - if let Some(parent) = path.parent() { - let _ = std::fs::create_dir_all(parent); - } - if let Ok(content) = serde_json::to_string(&active) { - let _ = std::fs::write(&path, content); - } -} - -pub fn finish_active_session(app: &AppHandle) { - let path = active_session_path(app); - let Ok(content) = std::fs::read_to_string(&path) else { return }; - let _ = std::fs::remove_file(&path); - let Ok(active) = serde_json::from_str::(&content) else { return }; - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - if now > active.start && now - active.start <= MAX_SESSION_SECONDS { - record_session(app, &active.instance_id, active.start, now); - } -} - -pub fn get_playtime(app: &AppHandle, instance_id: &str) -> PlaytimeResponse { - let data = load(app); - let sessions = data.sessions.get(instance_id); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let week_ago = now - 7 * 24 * 60 * 60; - let day_ago = now - 24 * 60 * 60; - let total_seconds: u64 = sessions.map_or(0, |s| s.iter().map(|s| s.end - s.start).sum()); - let week_seconds: u64 = sessions.map_or(0, |s| s.iter() - .filter(|s| s.start >= week_ago) - .map(|s| s.end - s.start) - .sum()); - let day_seconds: u64 = sessions.map_or(0, |s| s.iter() - .filter(|s| s.start >= day_ago) - .map(|s| s.end - s.start) - .sum()); - - PlaytimeResponse { total_seconds, week_seconds, day_seconds } -} - -#[derive(Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct PlaytimeDayEntry { - pub label: String, - pub seconds: u64, -} - -pub fn get_playtime_daily(app: &AppHandle, instance_id: &str, days: u64) -> Vec { - let data = load(app); - let sessions = data.sessions.get(instance_id); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - let day_secs = 24 * 60 * 60; - let mut entries: Vec<(u64, u64)> = (0..days).map(|d| { - let day_start = now - (d * day_secs) - (now % day_secs); - (day_start, 0) - }).collect(); - - if let Some(sessions) = sessions { - for session in sessions { - for entry in entries.iter_mut() { - let day_end = entry.0 + day_secs; - if session.start < day_end && session.end > entry.0 { - let overlap_start = std::cmp::max(session.start, entry.0); - let overlap_end = std::cmp::min(session.end, day_end); - if overlap_end > overlap_start { - entry.1 += overlap_end - overlap_start; - } - } - } - } - } - - entries.reverse(); - let day_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - entries.into_iter().map(|(ts, secs)| { - let weekday = ((ts / day_secs) + 4) % 7; - PlaytimeDayEntry { - label: day_names[weekday as usize].to_string(), - seconds: secs, - } - }).collect() -} diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs deleted file mode 100644 index a95f219..0000000 --- a/src-tauri/src/state.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; -use std::sync::atomic::AtomicBool; -use tokio::sync::Mutex; -use tokio_util::sync::CancellationToken; -pub struct DownloadState { - pub tokens: Arc>>, -} - -pub struct GameState { - pub child: Arc>>, - pub workshop_cancel: Arc>>, - pub manual_stop: Arc, -} - -pub struct ProxyGuard { - pub cancel_tokens: Arc>>, - pub local_port: Arc>>, -} diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs deleted file mode 100644 index 74164f2..0000000 --- a/src-tauri/src/types.rs +++ /dev/null @@ -1,152 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct McServer { - pub name: String, - pub ip: String, - pub port: u16, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct SkinLibraryItem { - pub id: String, - pub name: String, - pub skin_base64: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct CustomEdition { - pub id: String, - pub name: String, - pub desc: String, - pub url: String, - pub path: Option, - pub category: Option>, - pub logo: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct CustomizationEntry { - pub title_image: Option, - pub panorama: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct InstanceLaunchArgs { - pub values: std::collections::HashMap, - pub args: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct GoldMapperMapping { - pub from: String, - pub to: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct AppConfig { - pub username: String, - pub linux_runner: Option, - pub skin_base64: Option, - pub skin_library: Option>, - pub theme_style_id: Option, - pub theme_palette_id: Option, - pub apple_silicon_performance_boost: Option, - pub custom_editions: Option>, - pub customizations: Option>, - pub custom_paths: Option>, - pub profile: Option, - pub animations_enabled: Option, - pub vfx_enabled: Option, - pub rpc_enabled: Option, - pub start_fullscreen: Option, - pub music_vol: Option, - pub sfx_vol: Option, - pub legacy_mode: Option, - pub skip_intro: Option, - pub mangohud_enabled: Option, - pub saved_servers: Option>, - pub extra_launch_args: Option>, - pub launch_prefix: Option, - pub launch_env_vars: Option>, - pub instance_launch_args: Option>, - pub android_runner: Option, - pub android_audio_backend: Option, - pub goldmapper_enabled: Option, - pub goldmapper_mappings: Option>, - pub http_proxy: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ThemePalette { - pub id: String, - pub name: String, - pub colors: serde_json::Value, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Runner { - pub id: String, - pub name: String, - pub path: String, - pub r#type: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ScreenshotInfo { - pub path: String, - pub instance_id: String, - pub name: String, - pub date: u64, -} - -#[derive(Serialize)] -pub struct HttpResponse { - pub status: u16, - pub body: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct P2pEndpoint { - pub ip: String, - pub port: u16, -} - -#[derive(Serialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -#[cfg(target_os = "macos")] -pub struct MacosSetupProgressPayload { - pub stage: String, - pub message: String, - pub percent: Option, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkshopInstallRequest { - pub instance_id: String, - pub zips: std::collections::HashMap, - pub package_id: String, - pub version: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct InstalledWorkshopPackage { - pub id: String, - pub version: String, - pub dirs: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct InstalledPackageEntry { - pub instance_id: String, - pub package_id: String, - pub version: String, -} diff --git a/src-tauri/src/util.rs b/src-tauri/src/util.rs deleted file mode 100644 index 1a14eea..0000000 --- a/src-tauri/src/util.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use tauri::{AppHandle, Manager}; -use crate::config; -pub fn get_app_dir(app: &AppHandle) -> PathBuf { - app.path().app_local_data_dir().unwrap_or_else(|_| { - std::env::current_dir().unwrap_or_default() - }) -} - -pub fn get_config_path(app: &AppHandle) -> PathBuf { - get_app_dir(app).join("emerald_legacy_config.json") -} - -pub fn get_instance_working_dir(app: &AppHandle, instance_id: &str) -> PathBuf { - let root = get_app_dir(app); - let config = config::load_config_raw(app.clone()); - if let Some(ref editions) = config.custom_editions { - if let Some(edition) = editions.iter().find(|e| e.id == instance_id) { - if let Some(ref path) = edition.path { - return PathBuf::from(path); - } - } - } - if let Some(ref custom_paths) = config.custom_paths { - if let Some(path) = custom_paths.get(instance_id) { - return PathBuf::from(path); - } - } - root.join("instances").join(instance_id) -} - -pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - fs::create_dir_all(&dst)?; - for entry in fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - -pub fn build_http_client(proxy: Option<&str>) -> Result { - let mut builder = reqwest::Client::builder(); - builder = builder.user_agent("Emerald-Launcher"); - builder = builder - .connect_timeout(std::time::Duration::from_secs(15)) - .timeout(std::time::Duration::from_secs(500)); - if let Some(p) = proxy { - let trimmed = p.trim(); - if !trimmed.is_empty() { - let has_scheme = trimmed.contains("://"); - let full = if has_scheme { - trimmed.to_string() - } else { - format!("http://{}", trimmed) - }; - let proxy = reqwest::Proxy::all(&full).map_err(|e| format!("Invalid proxy: {e}"))?; - builder = builder.proxy(proxy); - } - } - builder.build().map_err(|e| e.to_string()) -} - -pub fn build_http_client_from_app(app: &AppHandle) -> Result { - let config = config::load_config_raw(app.clone()); - build_http_client(config.http_proxy.as_deref()) -} - -#[cfg(unix)] -pub fn unix_path_to_wine_z_path(unix_path: &PathBuf) -> String { - let p = unix_path.to_string_lossy(); - let mut out = String::with_capacity(p.len() + 3); - out.push_str("Z:"); - for ch in p.chars() { - if ch == '/' { - out.push('\\'); - } else { - out.push(ch); - } - } - out -} diff --git a/src-tauri/src/workshop_server.rs b/src-tauri/src/workshop_server.rs deleted file mode 100644 index 24e0382..0000000 --- a/src-tauri/src/workshop_server.rs +++ /dev/null @@ -1,134 +0,0 @@ -use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; -use tokio::net::TcpListener; -use tokio_util::sync::CancellationToken; -use tauri::{AppHandle, Emitter}; -const REGISTRY_URL: &str = "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main"; //neo: more hardcoding! -pub struct Guard { - cancel: Option, -} - -impl Guard { - pub fn new(cancel: CancellationToken) -> Self { - Self { cancel: Some(cancel) } - } -} - -impl Drop for Guard { - fn drop(&mut self) { - if let Some(cancel) = self.cancel.take() { - cancel.cancel(); - } - } -} - -pub async fn start(app: AppHandle) -> CancellationToken { - let cancel = CancellationToken::new(); - let server_cancel = cancel.clone(); - tokio::spawn(async move { - serve(app, server_cancel).await; - }); - - cancel -} - -async fn serve(app: AppHandle, cancel: CancellationToken) { - let listener = match TcpListener::bind("127.0.0.1:5582").await { //neo: dont say a word about this weird port. - Ok(l) => l, - Err(e) => { - let _ = app.emit("backend-error", format!("Workshop server failed to bind: {e}")); - eprintln!("[WorkshopServer] Failed to bind: {e}"); - return; - } - }; - - loop { - tokio::select! { - result = listener.accept() => { - match result { - Ok((stream, _)) => { - let handle_app = app.clone(); - tokio::spawn(handle(stream, handle_app)); - } - Err(e) => { - let _ = app.emit("backend-error", format!("Workshop server accept error: {e}")); - eprintln!("[WorkshopServer] Accept error: {e}"); - } - } - } - _ = cancel.cancelled() => break, - } - } -} - -async fn handle(stream: tokio::net::TcpStream, app: AppHandle) { - let (reader, mut writer) = stream.into_split(); - let mut buf_reader = BufReader::new(reader); - let mut request_line = String::new(); - if buf_reader.read_line(&mut request_line).await.is_err() { - return; - } - let request_line = request_line.trim(); - loop { - let mut line = String::new(); - if buf_reader.read_line(&mut line).await.is_err() { - return; - } - if line == "\r\n" || line == "\n" { - break; - } - } - - if request_line.starts_with("GET /workshop/") && request_line.ends_with(" HTTP/1.1") { - let path = &request_line["GET /workshop/".len()..request_line.len() - " HTTP/1.1".len()]; - match fetch_workshop_file(&app, path).await { - Ok(body) => { - let body_bytes = &body; - let content_type = if path.ends_with(".json") { - "application/json" - } else if path.ends_with(".png") { - "image/png" - } else { - "application/octet-stream" - }; - let response = format!( - "HTTP/1.1 200 OK\r\nContent-Type: {}\r\nContent-Length: {}\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n", - content_type, - body.len(), - ); - let _ = writer.write_all(response.as_bytes()).await; - let _ = writer.write_all(body_bytes).await; - } - Err(e) => { - let status = if e.contains("404") { 404 } else { 502 }; - let body = format!("{{\"error\": \"{e}\"}}"); - let response = format!( - "HTTP/1.1 {} {}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", - status, - if status == 404 { "Not Found" } else { "Bad Gateway" }, - body.len(), - body - ); - let _ = writer.write_all(response.as_bytes()).await; - } - } - } else { - let body = "{\"error\": \"not found\"}"; - let response = format!( - "HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", - body.len(), - body - ); - let _ = writer.write_all(response.as_bytes()).await; - } -} - -async fn fetch_workshop_file(app: &AppHandle, path: &str) -> Result, String> { - let url = format!("{}/{}", REGISTRY_URL, path); - let client = crate::util::build_http_client_from_app(app)?; - let resp = client.get(&url).send().await.map_err(|e| e.to_string())?; - if resp.status().is_success() { - resp.bytes().await.map(|b| b.to_vec()).map_err(|e| e.to_string()) - } else { - Err(format!("GitHub returned {}", resp.status())) - } -} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json deleted file mode 100644 index 15bd370..0000000 --- a/src-tauri/tauri.conf.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "LCE Emerald Launcher", - "version": "1.6.1", - "identifier": "com.emerald.legacy", - "build": { - "beforeDevCommand": "npm run dev", - "devUrl": "http://localhost:1420", - "beforeBuildCommand": "npm run build", - "frontendDist": "../dist" - }, - "app": { - "security": { - "assetProtocol": { - "enable": true, - "scope": { - "allow": ["**"], - "requireLiteralLeadingDot": false - } - } - }, - "windows": [ - { - "label": "main", - "title": "LCE Emerald Launcher", - "width": 1280, - "height": 720, - "minWidth": 1280, - "minHeight": 720, - "decorations": true, - "transparent": false, - "resizable": true, - "center": true, - "visible": true - } - ] - }, - "plugins": { - "deep-link": { - "desktop": { - "schemes": ["emerald", "discord-1482504445152460871", "emeraldlauncher"] - } - }, - "updater": { - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1NTk5MjQ4QjMxQjFCQgpSV1M3c1RHTEpKbFZBMEtxMnNUZ3F5V2FmQmQrREY5Z0pkbnJuUlBYL2d1cUtzRkJIeDFkUkR4RQo=", - "endpoints": [ - "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/latest/download/latest.json" - ], - "windows": { "installMode": "passive" } - } - }, - "bundle": { - "active": true, - "targets": "all", - "createUpdaterArtifacts": true, - "linux": { - "appimage": { - "bundleMediaFramework": true - } - }, - "resources": ["resources/DLC", "resources/GoldMapperLib.dll", "resources/GoldMapperLauncher.exe", "resources/SDL2.dll"], - "icon": [ - "icons/32x32.png", - "icons/64x64.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "macOS": { - "entitlements": null, - "exceptionDomain": "", - "frameworks": [], - "minimumSystemVersion": "10.15", - "signingIdentity": null - }, - "android": { - "minSdkVersion": 26, - "versionCode": 1006000 - } - } -} diff --git a/src-tauri/tauri.nightly.conf.json b/src-tauri/tauri.nightly.conf.json deleted file mode 100644 index 1da14ca..0000000 --- a/src-tauri/tauri.nightly.conf.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Emerald Legacy Launcher Nightly", - "version": "1.6.1-nightly", - "identifier": "com.emerald.legacy.nightly", - "build": { - "beforeDevCommand": "npm run dev", - "devUrl": "http://localhost:1420", - "beforeBuildCommand": "npm run build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "label": "main", - "title": "Emerald Legacy Launcher Nightly", - "width": 1280, - "height": 720, - "minWidth": 1280, - "minHeight": 720, - "decorations": true, - "transparent": false, - "resizable": true, - "center": true, - "visible": true - } - ] - }, - "plugins": { - "deep-link": { - "desktop": { - "schemes": ["emerald", "discord-1482504445152460871", "emeraldlauncher"] - } - }, - "updater": { - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1NTk5MjQ4QjMxQjFCQgpSV1M3c1RHTEpKbFZBMEtxMnNUZ3F5V2FmQmQrREY5Z0pkbnJuUlBYL2d1cUtzRkJIeDFkUkR4RQo=", - "endpoints": [ - "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/download/nightly/latest.json" - ], - "windows": { "installMode": "passive" } - } - }, - "bundle": { - "active": true, - "targets": "all", - "createUpdaterArtifacts": true, - "linux": { - "appimage": { - "bundleMediaFramework": true - } - }, - "resources": ["resources/DLC"], - "icon": [ - "icons/32x32.png", - "icons/64x64.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "macOS": { - "entitlements": null, - "exceptionDomain": "", - "frameworks": [], - "signingIdentity": null, - "providerShortName": "Emerald" - } - } -} diff --git a/src/App/Application.cpp b/src/App/Application.cpp new file mode 100644 index 0000000..cc5976e --- /dev/null +++ b/src/App/Application.cpp @@ -0,0 +1,302 @@ +#include "App/Application.hpp" +#include "Core/EmbeddedAssets.hpp" +#include "Core/Log.hpp" +#include "Core/Paths.hpp" +#include "Migration/Migration.hpp" +#include "Ui/EditionResolver.hpp" +#include +#include +#include +#include +namespace emerald::app { +namespace { +constexpr int kDefaultWindowWidth = 1280; +constexpr int kDefaultWindowHeight = 720; +constexpr const char *kWindowTitle = "Emerald Legacy Launcher"; +constexpr int kLogicalWidth = 1280; +constexpr int kLogicalHeight = 720; +std::filesystem::path env_directory(const char *name) { + const char *value = std::getenv(name); + if (value == nullptr || value[0] == '\0') { + return {}; + } + const std::filesystem::path path{value}; + return std::filesystem::is_directory(path) ? path : std::filesystem::path{}; +} + +std::filesystem::path bundle_root() { + static const std::filesystem::path root = [] { + const std::filesystem::path bundled = + core::app_data_dir() / "runtime" / + std::string(core::embedded::build_id()); + if (core::embedded::is_extracted(bundled)) { + return bundled; + } + if (core::embedded::extract_to(bundled)) { + return bundled; + } + core::warn("assets: failed to extract embedded resources"); + return bundled; + }(); + return root; +} + +std::filesystem::path resolve_root(const char *env, const char *name) { + if (const std::filesystem::path override = env_directory(env); + !override.empty()) { + return override; + } + const std::filesystem::path beside = core::executable_dir() / name; + if (std::filesystem::is_directory(beside)) { + return beside; + } + return bundle_root() / name; +} +} // namespace + +Application::Application() = default; +Application::~Application() { shutdown(); } +bool Application::initialize() { + SDL_SetAppMetadata("Emerald Legacy Launcher", EMERALD_VERSION, + "com.emerald.legacy"); + if (!SDL_Init(SDL_INIT_VIDEO)) { + core::error(std::string{"SDL_Init failed: "} + SDL_GetError()); + return false; + } + SDL_InitSubSystem(SDL_INIT_GAMEPAD); + { + int count = 0; + SDL_JoystickID *ids = SDL_GetGamepads(&count); + for (int i = 0; i < count; ++i) { + open_gamepad(ids[i]); + } + SDL_free(ids); + } + + window_ = SDL_CreateWindow(kWindowTitle, kDefaultWindowWidth, + kDefaultWindowHeight, SDL_WINDOW_RESIZABLE); + if (window_ == nullptr) { + core::error(std::string{"SDL_CreateWindow failed: "} + SDL_GetError()); + return false; + } + + renderer_ = SDL_CreateRenderer(window_, nullptr); + if (renderer_ == nullptr) { + core::error(std::string{"SDL_CreateRenderer failed: "} + SDL_GetError()); + return false; + } + + SDL_SetRenderVSync(renderer_, 1); + SDL_SetRenderLogicalPresentation(renderer_, kLogicalWidth, kLogicalHeight, + SDL_LOGICAL_PRESENTATION_LETTERBOX); + SDL_StartTextInput(window_); + core::info(":: starting up Emerald Launcher"); + core::info(std::string{" - app data dir: "} + core::app_data_dir().string()); + config_.load(); + core::info(std::string{" - username: "} + config_.data().username); + state_.load(); + const migration::MigrationReport report = + migration::run_migration(config_, state_); + if (report.ran) { + core::info(std::string{":: migration: files="} + + std::to_string(report.storage_files) + + " entries=" + std::to_string(report.entries) + + " mapped=" + std::to_string(report.mapped) + + " completed=" + (report.completed ? "true" : "false")); + } + discord_.configure(config_); + playtime_.load(); + const std::filesystem::path public_root = + resolve_root("EMERALD_PUBLIC_DIR", "public"); + const std::filesystem::path resource_root = + resolve_root("EMERALD_RESOURCE_DIR", "resources"); + const std::filesystem::path ui_docs_root = + resolve_root("EMERALD_UI_DOCS_DIR", "UiDocs"); + core::info(std::string{" - public dir: "} + public_root.string()); + core::info(std::string{" - resources dir: "} + resource_root.string()); + core::info(std::string{" - ui docs dir: "} + ui_docs_root.string()); + audio_.initialize(public_root); + audio_.set_music_volume(config_.data().music_vol.value_or(50)); + audio_.set_sfx_volume(config_.data().sfx_vol.value_or(100)); + ui_ = std::make_unique(renderer_, ui_docs_root, public_root, + resource_root / "i18n"); + if (!ui_->initialize()) { + core::error("ui: failed to initialize"); + return false; + } + + ui::UiServices services; + services.config = &config_; + services.playtime = &playtime_; + services.downloads = &downloads_; + services.launch = &launch_; + services.audio = &audio_; + services.dlc_source = resource_root / "DLC"; + services.skin_pck = core::app_data_dir() / "Skin.pck"; + launch_.configure(config_, playtime_, resource_root, core::app_data_dir(), + services.dlc_source, services.skin_pck); + download_revision_ = downloads_.revision(); + launch_revision_ = launch_.revision(); + macos_revision_ = launch_.macos_runtime().revision(); + services.quit = [this] { running_ = false; }; + ui_->set_services(services); + ui_->set_language(config_.data().language.value_or("en")); + ui_->navigate("home"); + audio_.start_music(); + return true; +} + +void Application::shutdown() { + audio_.shutdown(); + discord_.shutdown(); + ui_.reset(); + downloads_.shutdown(); + if (renderer_ != nullptr) { + SDL_DestroyRenderer(renderer_); + renderer_ = nullptr; + } + if (window_ != nullptr) { + SDL_DestroyWindow(window_); + window_ = nullptr; + } + if (SDL_WasInit(0) != 0) { + SDL_Quit(); + } +} + +void Application::handle_event(const SDL_Event &event) { + switch (event.type) { + case SDL_EVENT_QUIT: + running_ = false; + break; + case SDL_EVENT_KEY_DOWN: + if (ui_ != nullptr) { + ui_->handle_event(event); + } + break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_WHEEL: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_TEXT_INPUT: + if (ui_ != nullptr) { + ui_->handle_event(event); + } + break; + case SDL_EVENT_GAMEPAD_ADDED: + open_gamepad(event.gdevice.which); + if (ui_ != nullptr) { + ui_->handle_event(event); + } + break; + case SDL_EVENT_GAMEPAD_REMOVED: + close_gamepad(event.gdevice.which); + if (ui_ != nullptr) { + ui_->handle_event(event); + } + break; + case SDL_EVENT_WINDOW_MINIMIZED: + case SDL_EVENT_WINDOW_HIDDEN: + window_visible_ = false; + break; + case SDL_EVENT_WINDOW_RESTORED: + case SDL_EVENT_WINDOW_SHOWN: + window_visible_ = true; + break; + default: + break; + } +} + +void Application::open_gamepad(uint32_t instance_id) { + SDL_Gamepad *pad = SDL_OpenGamepad(instance_id); + if (pad != nullptr) { + gamepads_.push_back(pad); + } +} + +void Application::close_gamepad(uint32_t instance_id) { + for (auto it = gamepads_.begin(); it != gamepads_.end(); ++it) { + if (SDL_GetGamepadID(*it) == instance_id) { + SDL_CloseGamepad(*it); + gamepads_.erase(it); + break; + } + } +} + +void Application::render() { + if (ui_ == nullptr) { + return; + } + if (downloads_.revision() != download_revision_) { + download_revision_ = downloads_.revision(); + ui_->invalidate(); + } + launch_.poll(); + { + integrations::DiscordState drpc; + drpc.enabled = config_.data().rpc_enabled.value_or(true); + const launch::LaunchSnapshot snap = launch_.snapshot(); + drpc.running = snap.running; + drpc.username = config_.data().username; + drpc.view = ui_ ? ui_->current_view() : std::string(); + if (snap.running) { + drpc.instance_id = snap.instance_id; + if (const auto edition = + ui::find_config_edition(config_.data(), snap.instance_id)) { + drpc.version_name = edition->name; + drpc.instance_logo = edition->logo; + drpc.multiplayer = edition->lce_online; + } + } + const std::vector active_downloads = downloads_.active_ids(); + drpc.downloading_count = static_cast(active_downloads.size()); + if (!active_downloads.empty()) { + const std::string &first = active_downloads.front(); + drpc.downloading_id = first; + drpc.download_percent = + static_cast(downloads_.snapshot(first).percent); + if (const auto edition = ui::find_config_edition(config_.data(), first)) { + drpc.downloading_name = edition->name; + } else if (first.rfind("runner_", 0) == 0) { + drpc.downloading_name = first.substr(7); + } else { + drpc.downloading_name = "Game Files"; + } + } + discord_.update(drpc); + } + if (launch_.revision() != launch_revision_) { + launch_revision_ = launch_.revision(); + ui_->invalidate(); + } + if (launch_.macos_runtime().revision() != macos_revision_) { + macos_revision_ = launch_.macos_runtime().revision(); + ui_->invalidate(); + } + audio_.set_music_paused(launch_.snapshot().running || !window_visible_); + audio_.update(); + ui_->render(); +} + +int Application::run() { + if (!initialize()) { + shutdown(); + return 1; + } + + running_ = true; + while (running_) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + handle_event(event); + } + render(); + } + + shutdown(); + core::info(":: bye bye~"); + return 0; +} +} // namespace emerald::app diff --git a/src/App/Application.hpp b/src/App/Application.hpp new file mode 100644 index 0000000..363bf02 --- /dev/null +++ b/src/App/Application.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "Audio/AudioEngine.hpp" +#include "Config/ConfigStore.hpp" +#include "Instances/DownloadManager.hpp" +#include "Launch/LaunchService.hpp" +#include "Playtime/PlaytimeStore.hpp" +#include "State/StateStore.hpp" +#include "Integrations/DiscordRpc.hpp" +#include "Ui/UiSystem.hpp" +#include +#include +#include +#include +struct SDL_Window; +struct SDL_Renderer; +struct SDL_Gamepad; +namespace emerald::app { +class Application { +public: + Application(); + ~Application(); + Application(const Application &) = delete; + Application &operator=(const Application &) = delete; + Application(Application &&) = delete; + Application &operator=(Application &&) = delete; + int run(); + +private: + bool initialize(); + void shutdown(); + void handle_event(const SDL_Event &event); + void render(); + void open_gamepad(uint32_t instance_id); + void close_gamepad(uint32_t instance_id); + SDL_Window *window_ = nullptr; + SDL_Renderer *renderer_ = nullptr; + bool running_ = false; + config::ConfigStore config_; + playtime::PlaytimeStore playtime_; + state::StateStore state_; + instances::DownloadManager downloads_; + launch::LaunchService launch_; + std::unique_ptr ui_; + std::vector gamepads_; + integrations::DiscordRpc discord_; + audio::AudioEngine audio_; + bool window_visible_ = true; + uint64_t download_revision_ = 0; + uint64_t launch_revision_ = 0; + uint64_t macos_revision_ = 0; +}; +} // namespace emerald::app \ No newline at end of file diff --git a/src/Audio/AudioEngine.cpp b/src/Audio/AudioEngine.cpp new file mode 100644 index 0000000..50595b6 --- /dev/null +++ b/src/Audio/AudioEngine.cpp @@ -0,0 +1,251 @@ +#include "Audio/AudioEngine.hpp" +#include "Core/Log.hpp" +#include "miniaudio.h" +#include +#include +namespace emerald::audio { +namespace { +constexpr const char *kMusicTracks[] = { + "music/Moog City 2.ogg", "music/Blind Spots.ogg", + "music/Key.ogg", "music/Living Mice.ogg", + "music/Oxygene.ogg", "music/Subwoofer Lullaby.ogg", +}; +constexpr std::size_t kMusicTrackCount = + sizeof(kMusicTracks) / sizeof(kMusicTracks[0]); +constexpr const char *kPressSound = "press.wav"; +constexpr const char *kBackSound = "back.ogg"; +constexpr const char *kScrollSound = "scroll.ogg"; +constexpr const char *kSplashSound = "orb.ogg"; +constexpr ma_uint64 kFadeMilliseconds = 500; +constexpr ma_uint64 kPauseFadeMilliseconds = 300; +} // namespace + +struct AudioEngine::Impl { + ma_engine engine{}; + ma_sound_group music_group{}; + ma_sound_group sfx_group{}; + ma_sound music{}; + std::filesystem::path assets_root; + std::atomic track_finished{false}; + bool engine_ready = false; + bool music_group_ready = false; + bool sfx_group_ready = false; + bool music_loaded = false; + bool started = false; + bool paused = false; + std::size_t track = 0; + ma_uint64 pause_cursor = 0; + std::uint32_t music_volume = 50; + std::uint32_t sfx_volume = 100; + static void on_track_end(void *user_data, ma_sound *sound) { + (void)sound; + static_cast(user_data)->track_finished.store(true); + } + + void unload_music() { + if (!music_loaded) { + return; + } + ma_sound_stop(&music); + ma_sound_uninit(&music); + music_loaded = false; + } + + bool play_track(std::size_t index, bool fade) { + if (!engine_ready || kMusicTrackCount == 0) { + return false; + } + unload_music(); + track = index % kMusicTrackCount; + const std::filesystem::path path = assets_root / kMusicTracks[track]; + const ma_uint32 flags = MA_SOUND_FLAG_STREAM | + MA_SOUND_FLAG_NO_SPATIALIZATION | + MA_SOUND_FLAG_NO_PITCH; + const ma_result result = ma_sound_init_from_file( + &engine, path.string().c_str(), flags, &music_group, nullptr, &music); + if (result != MA_SUCCESS) { + core::warn(std::string{"audio: failed to load "} + path.string() + " (" + + ma_result_description(result) + ")"); + return false; + } + ma_sound_set_end_callback(&music, &Impl::on_track_end, this); + ma_sound_set_volume(&music, 1.0F); + if (fade) { + ma_sound_set_fade_in_milliseconds(&music, 0.0F, 1.0F, kFadeMilliseconds); + } + ma_sound_start(&music); + music_loaded = true; + return true; + } +}; + +AudioEngine::AudioEngine() : impl_(std::make_unique()) {} +AudioEngine::~AudioEngine() { shutdown(); } +bool AudioEngine::initialize(std::filesystem::path assets_root) { + if (impl_->engine_ready) { + return true; + } + impl_->assets_root = std::move(assets_root); + ma_engine_config config = ma_engine_config_init(); + const ma_result result = ma_engine_init(&config, &impl_->engine); + if (result != MA_SUCCESS) { + core::warn(std::string{"audio: engine unavailable ("} + + ma_result_description(result) + ")"); + return false; + } + impl_->engine_ready = true; + if (ma_sound_group_init(&impl_->engine, MA_SOUND_FLAG_NO_SPATIALIZATION, + nullptr, &impl_->music_group) == MA_SUCCESS) { + impl_->music_group_ready = true; + } + if (ma_sound_group_init(&impl_->engine, MA_SOUND_FLAG_NO_SPATIALIZATION, + nullptr, &impl_->sfx_group) == MA_SUCCESS) { + impl_->sfx_group_ready = true; + } + core::info(":: audio engine ready"); + return true; +} + +void AudioEngine::shutdown() { + if (impl_ == nullptr) { + return; + } + impl_->unload_music(); + if (impl_->music_group_ready) { + ma_sound_group_uninit(&impl_->music_group); + impl_->music_group_ready = false; + } + if (impl_->sfx_group_ready) { + ma_sound_group_uninit(&impl_->sfx_group); + impl_->sfx_group_ready = false; + } + if (impl_->engine_ready) { + ma_engine_uninit(&impl_->engine); + impl_->engine_ready = false; + } + impl_->started = false; + impl_->paused = false; +} + +bool AudioEngine::available() const { + return impl_ != nullptr && impl_->engine_ready; +} + +void AudioEngine::set_music_volume(std::uint32_t volume) { + impl_->music_volume = volume; + if (!impl_->music_group_ready) { + return; + } + ma_sound_group_set_volume(&impl_->music_group, + static_cast(volume) / 100.0F); +} + +void AudioEngine::set_sfx_volume(std::uint32_t volume) { + impl_->sfx_volume = volume; + if (!impl_->sfx_group_ready) { + return; + } + ma_sound_group_set_volume(&impl_->sfx_group, + static_cast(volume) / 100.0F); +} + +std::uint32_t AudioEngine::music_volume() const { return impl_->music_volume; } +std::uint32_t AudioEngine::sfx_volume() const { return impl_->sfx_volume; } +void AudioEngine::play_sfx(std::string_view name) { + if (!impl_->engine_ready || !impl_->sfx_group_ready || name.empty()) { + return; + } + const std::filesystem::path path = + impl_->assets_root / "sounds" / std::string(name); + ma_engine_play_sound(&impl_->engine, path.string().c_str(), + &impl_->sfx_group); +} + +void AudioEngine::play_press() { play_sfx(kPressSound); } +void AudioEngine::play_back() { play_sfx(kBackSound); } +void AudioEngine::play_scroll() { play_sfx(kScrollSound); } +void AudioEngine::play_splash() { play_sfx(kSplashSound); } +void AudioEngine::start_music() { + if (!impl_->engine_ready || impl_->started) { + return; + } + impl_->started = true; + impl_->paused = false; + impl_->play_track(0, true); +} + +void AudioEngine::stop_music() { + impl_->unload_music(); + impl_->started = false; + impl_->paused = false; +} + +void AudioEngine::skip_track(int direction) { + if (!impl_->engine_ready || !impl_->started) { + return; + } + const int count = static_cast(kMusicTrackCount); + int next = (static_cast(impl_->track) + direction) % count; + if (next < 0) { + next += count; + } + impl_->track_finished.store(false); + impl_->play_track(static_cast(next), true); +} + +void AudioEngine::set_music_paused(bool paused) { + if (impl_->paused == paused) { + return; + } + impl_->paused = paused; + if (!impl_->engine_ready || !impl_->started) { + return; + } + if (paused) { + if (impl_->music_loaded) { + ma_sound_get_cursor_in_pcm_frames(&impl_->music, &impl_->pause_cursor); + ma_sound_set_fade_in_milliseconds(&impl_->music, -1.0F, 0.0F, + kPauseFadeMilliseconds); + const ma_uint64 now = ma_engine_get_time_in_milliseconds(&impl_->engine); + ma_sound_set_stop_time_in_milliseconds(&impl_->music, + now + kPauseFadeMilliseconds + 20); + } + return; + } + if (impl_->music_loaded) { + ma_sound_reset_stop_time_and_fade(&impl_->music); + ma_sound_seek_to_pcm_frame(&impl_->music, impl_->pause_cursor); + ma_sound_set_volume(&impl_->music, 1.0F); + ma_sound_set_fade_in_milliseconds(&impl_->music, 0.0F, 1.0F, + kFadeMilliseconds); + ma_sound_start(&impl_->music); + return; + } + impl_->play_track(impl_->track, true); +} + +bool AudioEngine::music_paused() const { return impl_->paused; } +bool AudioEngine::music_playing() const { + return impl_->music_loaded && ma_sound_is_playing(&impl_->music) != 0; +} + +std::string AudioEngine::current_track_name() const { + if (!impl_->started) { + return {}; + } + return std::filesystem::path(kMusicTracks[impl_->track]).stem().string(); +} + +void AudioEngine::update() { + if (!impl_->engine_ready) { + return; + } + if (!impl_->track_finished.exchange(false)) { + return; + } + if (!impl_->started || impl_->paused) { + return; + } + impl_->play_track((impl_->track + 1) % kMusicTrackCount, true); +} +} // namespace emerald::audio diff --git a/src/Audio/AudioEngine.hpp b/src/Audio/AudioEngine.hpp new file mode 100644 index 0000000..d76060a --- /dev/null +++ b/src/Audio/AudioEngine.hpp @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#include +#include +#include +namespace emerald::audio { +class AudioEngine { +public: + AudioEngine(); + ~AudioEngine(); + AudioEngine(const AudioEngine &) = delete; + AudioEngine &operator=(const AudioEngine &) = delete; + AudioEngine(AudioEngine &&) = delete; + AudioEngine &operator=(AudioEngine &&) = delete; + bool initialize(std::filesystem::path assets_root); + void shutdown(); + bool available() const; + void set_music_volume(std::uint32_t volume); + void set_sfx_volume(std::uint32_t volume); + std::uint32_t music_volume() const; + std::uint32_t sfx_volume() const; + void play_sfx(std::string_view name); + void play_press(); + void play_back(); + void play_scroll(); + void play_splash(); + void start_music(); + void stop_music(); + void skip_track(int direction = 1); + void set_music_paused(bool paused); + bool music_paused() const; + bool music_playing() const; + std::string current_track_name() const; + void update(); + +private: + struct Impl; + std::unique_ptr impl_; +}; +} // namespace emerald::audio diff --git a/src/Audio/MiniaudioImpl.cpp b/src/Audio/MiniaudioImpl.cpp new file mode 100644 index 0000000..8f22448 --- /dev/null +++ b/src/Audio/MiniaudioImpl.cpp @@ -0,0 +1,10 @@ +#ifdef EMERALD_MINIAUDIO_VORBIS +#define STB_VORBIS_HEADER_ONLY +#include "extras/stb_vorbis.c" +#endif +#define MINIAUDIO_IMPLEMENTATION +#include "miniaudio.h" +#ifdef EMERALD_MINIAUDIO_VORBIS +#undef STB_VORBIS_HEADER_ONLY +#include "extras/stb_vorbis.c" +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..8ac7dc9 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,190 @@ +set(EMERALD_GENERATED_DIR "${CMAKE_BINARY_DIR}/generated") +file(MAKE_DIRECTORY "${EMERALD_GENERATED_DIR}") +set(EMERALD_EMBED_OUTPUT "${EMERALD_GENERATED_DIR}/EmbeddedAssets.cpp") +add_executable(emerald_embed "${CMAKE_SOURCE_DIR}/tools/EmbedAssets.cpp") +set_target_properties(emerald_embed PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tools" +) + +file(GLOB_RECURSE EMERALD_ASSET_FILES CONFIGURE_DEPENDS + "${EMERALD_PUBLIC_DIR}/*" + "${EMERALD_RESOURCE_DIR}/*" + "${EMERALD_UI_DOCS_DIR}/*" +) + +add_custom_command( + OUTPUT "${EMERALD_EMBED_OUTPUT}" + COMMAND emerald_embed "${EMERALD_EMBED_OUTPUT}" + public "${EMERALD_PUBLIC_DIR}" + resources "${EMERALD_RESOURCE_DIR}" + UiDocs "${EMERALD_UI_DOCS_DIR}" + DEPENDS emerald_embed ${EMERALD_ASSET_FILES} + COMMENT "Embedding public/, resources/ and UiDocs/ into the executable" + VERBATIM +) + +set(EMERALD_CORE_SOURCES + Core/EmbeddedAssets.cpp + ${EMERALD_EMBED_OUTPUT} + Core/Fs.cpp + Core/Log.cpp + Core/Paths.cpp + Config/ConfigSchema.cpp + Config/ConfigStore.cpp + Platform/Platform.cpp + Platform/Process.cpp + Launch/Servers.cpp + Launch/GoldMapper.cpp + Launch/LaunchPlan.cpp + Launch/GameLauncher.cpp + Launch/MacosRuntime.cpp + Launch/LaunchService.cpp + Instances/InstanceManager.cpp + Instances/ArgsSchema.cpp + Instances/Downloader.cpp + Instances/Installer.cpp + Instances/Dlc.cpp + Instances/Backup.cpp + Instances/Editions.cpp + Instances/DownloadManager.cpp + Instances/InstanceSync.cpp + Instances/Runners.cpp + Instances/Workshop.cpp + Net/HttpClient.cpp + Playtime/PlaytimeStore.cpp + State/StateStore.cpp + Migration/Migration.cpp +) + +if(WIN32) + list(APPEND EMERALD_CORE_SOURCES Migration/LeveldbStorage.cpp) +else() + list(APPEND EMERALD_CORE_SOURCES Migration/WebkitStorage.cpp) +endif() +add_library(emerald_core STATIC ${EMERALD_CORE_SOURCES}) +target_include_directories(emerald_core + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(emerald_core + PUBLIC + SDL3::SDL3 + nlohmann_json::nlohmann_json +) + +if(NOT WIN32) + target_link_libraries(emerald_core PRIVATE SQLite::SQLite3) +endif() +target_link_libraries(emerald_core + PRIVATE + CURL::libcurl + PkgConfig::EMERALD_ARCHIVE +) + +emerald_apply_warnings(emerald_core) +find_package(Threads REQUIRED) +add_library(emerald_miniaudio STATIC Audio/MiniaudioImpl.cpp) +target_include_directories(emerald_miniaudio SYSTEM PUBLIC "${EMERALD_MINIAUDIO_INCLUDE_DIR}") +if(EXISTS "${EMERALD_MINIAUDIO_INCLUDE_DIR}/extras/stb_vorbis.c") + target_compile_definitions(emerald_miniaudio PRIVATE EMERALD_MINIAUDIO_VORBIS) +endif() +if(WIN32) + target_link_libraries(emerald_miniaudio PUBLIC winmm ole32 user32) +elseif(APPLE) + target_link_libraries(emerald_miniaudio PUBLIC + Threads::Threads + "-framework CoreFoundation" + "-framework CoreAudio" + "-framework AudioToolbox" + ) +else() + target_link_libraries(emerald_miniaudio PUBLIC + Threads::Threads + ${CMAKE_DL_LIBS} + m + ) +endif() + +add_library(emerald_audio STATIC + Audio/AudioEngine.cpp +) + +target_link_libraries(emerald_audio + PUBLIC + emerald_core + PRIVATE + emerald_miniaudio +) + +emerald_apply_warnings(emerald_audio) +set(EMERALD_UI_SOURCES + Ui/Style.cpp + Ui/Element.cpp + Ui/EditionResolver.cpp + Ui/Binding.cpp + Ui/I18n.cpp + Ui/Xml.cpp + Ui/Handlers.cpp + Ui/UiSystem.cpp + Ui/Render/TextureCache.cpp + Ui/Render/SvgRaster.cpp + Ui/Render/FontCache.cpp + Ui/Render/Panorama.cpp + Ui/Render/SdlRenderer.cpp + Ui/Views/HomeView.cpp + Ui/Views/SettingsView.cpp + Ui/Views/VersionsView.cpp + Ui/Views/CreditsView.cpp +) + +add_library(emerald_ui STATIC ${EMERALD_UI_SOURCES}) +target_include_directories(emerald_ui PRIVATE "${CMAKE_SOURCE_DIR}/third_party/nanosvg") +target_link_libraries(emerald_ui + PUBLIC + emerald_core + emerald_audio + PRIVATE + SDL3::SDL3 + SDL3_ttf::SDL3_ttf + pugixml::pugixml + emerald_stb +) + +emerald_apply_warnings(emerald_ui) +add_executable(emerald + WIN32 + MACOSX_BUNDLE + Main.cpp + App/Application.cpp +) + +target_link_libraries(emerald + PRIVATE + emerald_ui + emerald_integrations + discord_ipc_cpp +) + +emerald_apply_warnings(emerald) +set_target_properties(emerald PROPERTIES + MACOSX_BUNDLE_BUNDLE_NAME "Emerald Legacy Launcher" + MACOSX_BUNDLE_GUI_IDENTIFIER "com.emerald.legacy" + MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" + OUTPUT_NAME "emerald-legacy-launcher" +) +set(EMERALD_INTEGRATIONS_SOURCES + Integrations/DiscordRpc.cpp +) +add_library(emerald_integrations STATIC ${EMERALD_INTEGRATIONS_SOURCES}) +target_link_libraries(emerald_integrations + PUBLIC + emerald_core + PRIVATE + CURL::libcurl +) + +emerald_apply_warnings(emerald_integrations) +add_subdirectory(discord_ipc_cpp) +target_include_directories(emerald_integrations PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/discord_ipc_cpp/include") diff --git a/src/Config/ConfigSchema.cpp b/src/Config/ConfigSchema.cpp new file mode 100644 index 0000000..07df0b8 --- /dev/null +++ b/src/Config/ConfigSchema.cpp @@ -0,0 +1,376 @@ +#include "Config/ConfigSchema.hpp" +namespace emerald::config { +namespace { +const Json &require_object(const Json &value) { + static const Json empty = Json::object(); + return value.is_object() ? value : empty; +} + +McServer server_from_json(const Json &object) { + McServer server; + server.name = object.value("name", std::string{}); + server.ip = object.value("ip", std::string{}); + server.port = object.value("port", static_cast(0)); + return server; +} + +Json server_to_json(const McServer &server) { + return Json{ + {"name", server.name}, + {"ip", server.ip}, + {"port", server.port}, + }; +} + +SkinLibraryItem skin_from_json(const Json &object) { + SkinLibraryItem item; + item.id = object.value("id", std::string{}); + item.name = object.value("name", std::string{}); + item.skin_base64 = object.value("skinBase64", std::string{}); + return item; +} + +Json skin_to_json(const SkinLibraryItem &item) { + return Json{ + {"id", item.id}, + {"name", item.name}, + {"skinBase64", item.skin_base64}, + }; +} + +CustomEdition edition_from_json(const Json &object) { + CustomEdition edition; + edition.id = object.value("id", std::string{}); + edition.name = object.value("name", std::string{}); + edition.desc = object.value("desc", std::string{}); + edition.url = object.value("url", std::string{}); + edition.path = json_optional(object, "path"); + if (object.contains("category") && object["category"].is_array()) { + edition.category = object["category"].get>(); + } + edition.logo = json_optional(object, "logo"); + return edition; +} + +Json edition_to_json(const CustomEdition &edition) { + Json object{ + {"id", edition.id}, + {"name", edition.name}, + {"desc", edition.desc}, + {"url", edition.url}, + }; + json_set(object, "path", edition.path); + if (edition.category.has_value()) { + object["category"] = *edition.category; + } else { + object["category"] = nullptr; + } + json_set(object, "logo", edition.logo); + return object; +} + +CustomizationEntry customization_from_json(const Json &object) { + CustomizationEntry entry; + entry.title_image = json_optional(object, "titleImage"); + entry.panorama = json_optional(object, "panorama"); + return entry; +} + +Json customization_to_json(const CustomizationEntry &entry) { + Json object = Json::object(); + json_set(object, "titleImage", entry.title_image); + json_set(object, "panorama", entry.panorama); + return object; +} + +InstanceLaunchArgs instance_args_from_json(const Json &object) { + InstanceLaunchArgs args; + if (object.contains("values") && object["values"].is_object()) { + args.values = object["values"]; + } + if (object.contains("args") && object["args"].is_array()) { + args.args = object["args"].get>(); + } + return args; +} + +Json instance_args_to_json(const InstanceLaunchArgs &args) { + return Json{ + {"values", args.values}, + {"args", args.args}, + }; +} + +GoldMapperMapping mapping_from_json(const Json &object) { + GoldMapperMapping mapping; + mapping.from = object.value("from", std::string{}); + mapping.to = object.value("to", std::string{}); + return mapping; +} + +Json mapping_to_json(const GoldMapperMapping &mapping) { + return Json{ + {"from", mapping.from}, + {"to", mapping.to}, + }; +} + +SavedCape cape_from_json(const Json &object) { + SavedCape cape; + cape.id = object.value("id", std::string{}); + cape.name = object.value("name", std::string{}); + cape.url = object.value("url", std::string{}); + return cape; +} + +Json cape_to_json(const SavedCape &cape) { + return Json{ + {"id", cape.id}, + {"name", cape.name}, + {"url", cape.url}, + }; +} + +SavedSkin saved_skin_from_json(const Json &object) { + SavedSkin skin; + skin.id = object.value("id", std::string{}); + skin.name = object.value("name", std::string{}); + skin.url = object.value("url", std::string{}); + skin.is_slim = json_optional(object, "isSlim"); + return skin; +} + +Json saved_skin_to_json(const SavedSkin &skin) { + Json object{ + {"id", skin.id}, + {"name", skin.name}, + {"url", skin.url}, + }; + json_set(object, "isSlim", skin.is_slim); + return object; +} + +template +auto map_vector(const Json &object, const char *key, Convert convert) + -> std::optional> { + if (!object.contains(key) || !object[key].is_array()) { + return std::nullopt; + } + std::vector items; + items.reserve(object[key].size()); + for (const Json &entry : object[key]) { + items.push_back(convert(entry)); + } + return items; +} + +template +Json vector_to_json(const std::optional> &items, + Convert convert) { + if (!items.has_value()) { + return nullptr; + } + Json array = Json::array(); + for (const T &item : *items) { + array.push_back(convert(item)); + } + return array; +} + +} // namespace + +Json to_json(const AppConfig &config) { + Json object = Json::object(); + object["username"] = config.username; + json_set(object, "linuxRunner", config.linux_runner); + json_set(object, "skinBase64", config.skin_base64); + object["skinLibrary"] = vector_to_json(config.skin_library, skin_to_json); + json_set(object, "themeStyleId", config.theme_style_id); + json_set(object, "themePaletteId", config.theme_palette_id); + json_set(object, "appleSiliconPerformanceBoost", + config.apple_silicon_performance_boost); + object["customEditions"] = + vector_to_json(config.custom_editions, edition_to_json); + if (config.customizations.has_value()) { + Json customizations = Json::object(); + for (const auto &[key, entry] : *config.customizations) { + customizations[key] = customization_to_json(entry); + } + object["customizations"] = std::move(customizations); + } else { + object["customizations"] = nullptr; + } + if (config.custom_paths.has_value()) { + object["customPaths"] = *config.custom_paths; + } else { + object["customPaths"] = nullptr; + } + json_set(object, "profile", config.profile); + json_set(object, "animationsEnabled", config.animations_enabled); + json_set(object, "vfxEnabled", config.vfx_enabled); + json_set(object, "rpcEnabled", config.rpc_enabled); + json_set(object, "startFullscreen", config.start_fullscreen); + json_set(object, "musicVol", config.music_vol); + json_set(object, "sfxVol", config.sfx_vol); + json_set(object, "legacyMode", config.legacy_mode); + json_set(object, "skipIntro", config.skip_intro); + json_set(object, "mangohudEnabled", config.mangohud_enabled); + object["savedServers"] = vector_to_json(config.saved_servers, server_to_json); + json_set(object, "extraLaunchArgs", config.extra_launch_args); + json_set(object, "launchPrefix", config.launch_prefix); + if (config.launch_env_vars.has_value()) { + object["launchEnvVars"] = *config.launch_env_vars; + } else { + object["launchEnvVars"] = nullptr; + } + if (config.instance_launch_args.has_value()) { + Json instance_args = Json::object(); + for (const auto &[key, args] : *config.instance_launch_args) { + instance_args[key] = instance_args_to_json(args); + } + object["instanceLaunchArgs"] = std::move(instance_args); + } else { + object["instanceLaunchArgs"] = nullptr; + } + json_set(object, "androidRunner", config.android_runner); + json_set(object, "androidAudioBackend", config.android_audio_backend); + json_set(object, "goldmapperEnabled", config.goldmapper_enabled); + object["goldmapperMappings"] = + vector_to_json(config.goldmapper_mappings, mapping_to_json); + json_set(object, "httpProxy", config.http_proxy); + object["customCapes"] = vector_to_json(config.custom_capes, cape_to_json); + object["customSkins"] = + vector_to_json(config.custom_skins, saved_skin_to_json); + json_set(object, "skinSlim", config.skin_slim); + json_set(object, "skinSource", config.skin_source); + json_set(object, "capeBase64", config.cape_base64); + json_set(object, "capeSource", config.cape_source); + json_set(object, "language", config.language); + json_set(object, "setupCompleted", config.setup_completed); + json_set(object, "layout", config.layout); + json_set(object, "daytime", config.daytime); + json_set(object, "keepOpen", config.keep_open); + json_set(object, "trayIcon", config.tray_icon); + json_set(object, "showLayers", config.show_layers); + json_set(object, "macosRuntimeInstalled", config.macos_runtime_installed); + return object; +} + +AppConfig from_json(const Json &object_value) { + const Json &object = require_object(object_value); + AppConfig config; + config.username = object.value("username", std::string{"Player"}); + config.linux_runner = json_optional(object, "linuxRunner"); + config.skin_base64 = json_optional(object, "skinBase64"); + config.skin_library = + map_vector(object, "skinLibrary", skin_from_json); + config.theme_style_id = json_optional(object, "themeStyleId"); + config.theme_palette_id = + json_optional(object, "themePaletteId"); + config.apple_silicon_performance_boost = + json_optional(object, "appleSiliconPerformanceBoost"); + config.custom_editions = + map_vector(object, "customEditions", edition_from_json); + if (object.contains("customizations") && + object["customizations"].is_object()) { + std::unordered_map customizations; + for (const auto &[key, value] : object["customizations"].items()) { + customizations[key] = customization_from_json(value); + } + config.customizations = std::move(customizations); + } + if (object.contains("customPaths") && object["customPaths"].is_object()) { + config.custom_paths = + object["customPaths"] + .get>(); + } + config.profile = json_optional(object, "profile"); + config.animations_enabled = json_optional(object, "animationsEnabled"); + config.vfx_enabled = json_optional(object, "vfxEnabled"); + config.rpc_enabled = json_optional(object, "rpcEnabled"); + config.start_fullscreen = json_optional(object, "startFullscreen"); + config.music_vol = json_optional(object, "musicVol"); + config.sfx_vol = json_optional(object, "sfxVol"); + config.legacy_mode = json_optional(object, "legacyMode"); + config.skip_intro = json_optional(object, "skipIntro"); + config.mangohud_enabled = json_optional(object, "mangohudEnabled"); + config.saved_servers = + map_vector(object, "savedServers", server_from_json); + config.extra_launch_args = + json_optional>(object, "extraLaunchArgs"); + config.launch_prefix = json_optional(object, "launchPrefix"); + if (object.contains("launchEnvVars") && object["launchEnvVars"].is_object()) { + config.launch_env_vars = + object["launchEnvVars"] + .get>(); + } + if (object.contains("instanceLaunchArgs") && + object["instanceLaunchArgs"].is_object()) { + std::unordered_map instance_args; + for (const auto &[key, value] : object["instanceLaunchArgs"].items()) { + instance_args[key] = instance_args_from_json(value); + } + config.instance_launch_args = std::move(instance_args); + } + config.android_runner = json_optional(object, "androidRunner"); + config.android_audio_backend = + json_optional(object, "androidAudioBackend"); + config.goldmapper_enabled = json_optional(object, "goldmapperEnabled"); + config.goldmapper_mappings = map_vector( + object, "goldmapperMappings", mapping_from_json); + config.http_proxy = json_optional(object, "httpProxy"); + + config.custom_capes = + map_vector(object, "customCapes", cape_from_json); + config.custom_skins = + map_vector(object, "customSkins", saved_skin_from_json); + config.skin_slim = json_optional(object, "skinSlim"); + config.skin_source = json_optional(object, "skinSource"); + config.cape_base64 = json_optional(object, "capeBase64"); + config.cape_source = json_optional(object, "capeSource"); + config.language = json_optional(object, "language"); + config.setup_completed = json_optional(object, "setupCompleted"); + config.layout = json_optional(object, "layout"); + config.daytime = json_optional(object, "daytime"); + config.keep_open = json_optional(object, "keepOpen"); + config.tray_icon = json_optional(object, "trayIcon"); + config.show_layers = json_optional(object, "showLayers"); + config.macos_runtime_installed = + json_optional(object, "macosRuntimeInstalled"); + + return config; +} + +void apply_legacy_defaults(AppConfig &config) { + if (!config.profile.has_value()) { + config.profile = "legacy_evolved"; + } + if (!config.animations_enabled.has_value()) { + config.animations_enabled = true; + } + if (!config.vfx_enabled.has_value()) { + config.vfx_enabled = true; + } + if (!config.rpc_enabled.has_value()) { + config.rpc_enabled = true; + } + if (!config.start_fullscreen.has_value()) { + config.start_fullscreen = false; + } + if (!config.music_vol.has_value()) { + config.music_vol = 50; + } + if (!config.sfx_vol.has_value()) { + config.sfx_vol = 100; + } + if (!config.legacy_mode.has_value()) { + config.legacy_mode = false; + } + if (!config.skip_intro.has_value()) { + config.skip_intro = false; + } + if (!config.goldmapper_enabled.has_value()) { + config.goldmapper_enabled = false; + } +} +} // namespace emerald::config diff --git a/src/Config/ConfigSchema.hpp b/src/Config/ConfigSchema.hpp new file mode 100644 index 0000000..3c8e9b6 --- /dev/null +++ b/src/Config/ConfigSchema.hpp @@ -0,0 +1,111 @@ +#pragma once +#include "Core/Json.hpp" +#include +#include +#include +#include +#include +namespace emerald::config { +struct McServer { + std::string name; + std::string ip; + std::uint16_t port = 0; +}; + +struct SkinLibraryItem { + std::string id; + std::string name; + std::string skin_base64; +}; + +struct CustomEdition { + std::string id; + std::string name; + std::string desc; + std::string url; + std::optional path; + std::optional> category; + std::optional logo; +}; + +struct CustomizationEntry { + std::optional title_image; + std::optional panorama; +}; + +struct InstanceLaunchArgs { + Json values = Json::object(); + std::vector args; +}; + +struct GoldMapperMapping { + std::string from; + std::string to; +}; + +struct SavedCape { + std::string id; + std::string name; + std::string url; +}; + +struct SavedSkin { + std::string id; + std::string name; + std::string url; + std::optional is_slim; +}; + +struct AppConfig { + std::string username = "Player"; + std::optional linux_runner; + std::optional skin_base64; + std::optional> skin_library; + std::optional theme_style_id; + std::optional theme_palette_id; + std::optional apple_silicon_performance_boost; + std::optional> custom_editions; + std::optional> + customizations; + std::optional> custom_paths; + std::optional profile; + std::optional animations_enabled; + std::optional vfx_enabled; + std::optional rpc_enabled; + std::optional start_fullscreen; + std::optional music_vol; + std::optional sfx_vol; + std::optional legacy_mode; + std::optional skip_intro; + std::optional mangohud_enabled; + std::optional> saved_servers; + std::optional> extra_launch_args; + std::optional launch_prefix; + std::optional> launch_env_vars; + std::optional> + instance_launch_args; + std::optional android_runner; + std::optional android_audio_backend; + std::optional goldmapper_enabled; + std::optional> goldmapper_mappings; + std::optional http_proxy; + std::optional> custom_capes; + std::optional> custom_skins; + std::optional skin_slim; + std::optional skin_source; + std::optional cape_base64; + std::optional cape_source; + std::optional language; + std::optional setup_completed; + std::optional layout; + std::optional daytime; + std::optional keep_open; + std::optional tray_icon; + std::optional show_layers; + std::optional macos_runtime_installed; +}; + +Json to_json(const AppConfig &config); +AppConfig from_json(const Json &object); +void apply_legacy_defaults(AppConfig &config); +} // namespace emerald::config diff --git a/src/Config/ConfigStore.cpp b/src/Config/ConfigStore.cpp new file mode 100644 index 0000000..8d227eb --- /dev/null +++ b/src/Config/ConfigStore.cpp @@ -0,0 +1,72 @@ +#include "Config/ConfigStore.hpp" +#include "Core/Fs.hpp" +#include "Core/Log.hpp" +#include "Core/Paths.hpp" +#include +namespace emerald::config { +namespace { +std::filesystem::path legacy_username_path() { + return core::app_data_dir() / "emerald_legacy_config.txt"; +} + +Json merge_known_fields(const Json &document, const AppConfig &config) { + Json merged = document.is_object() ? document : Json::object(); + Json known = to_json(config); + for (auto &[key, value] : known.items()) { + merged[key] = value; + } + return merged; +} +} // namespace + +void ConfigStore::load() { + document_ = Json::object(); + const std::filesystem::path path = core::config_file_path(); + if (auto contents = core::read_file(path)) { + Json parsed = Json::parse(*contents, nullptr, false); + if (!parsed.is_discarded() && parsed.is_object()) { + config_ = from_json(parsed); + document_ = parsed; + return; + } + core::warn("config file is not valid JSON, falling back to legacy"); + } + + config_ = AppConfig{}; + if (auto legacy = core::read_file(legacy_username_path())) { + std::string username = *legacy; + while (!username.empty() && + (username.back() == '\n' || username.back() == '\r')) { + username.pop_back(); + } + if (!username.empty()) { + config_.username = username; + } + } + + apply_legacy_defaults(config_); +} + +bool ConfigStore::save() const { + const Json merged = merge_known_fields(document_, config_); + return core::write_file_atomic(core::config_file_path(), merged.dump()); +} + +std::string ConfigStore::export_pretty() const { + return to_json(config_).dump(2); +} + +bool ConfigStore::import_from_string(std::string_view contents, + std::string &error) { + Json parsed = Json::parse(contents, nullptr, false); + if (parsed.is_discarded() || !parsed.is_object()) { + error = "settings file is not a valid JSON object"; + return false; + } + + config_ = from_json(parsed); + document_ = parsed; + save(); + return true; +} +} // namespace emerald::config diff --git a/src/Config/ConfigStore.hpp b/src/Config/ConfigStore.hpp new file mode 100644 index 0000000..6143aa9 --- /dev/null +++ b/src/Config/ConfigStore.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "Config/ConfigSchema.hpp" +#include "Core/Json.hpp" +#include +#include +namespace emerald::config { +class ConfigStore { +public: + void load(); + bool save() const; + AppConfig &data() { return config_; } + const AppConfig &data() const { return config_; } + const Json &document() const { return document_; } + std::string export_pretty() const; + bool import_from_string(std::string_view contents, std::string &error); + +private: + AppConfig config_; + Json document_ = Json::object(); +}; +} // namespace emerald::config diff --git a/src/Core/EmbeddedAssets.cpp b/src/Core/EmbeddedAssets.cpp new file mode 100644 index 0000000..f6791e4 --- /dev/null +++ b/src/Core/EmbeddedAssets.cpp @@ -0,0 +1,62 @@ +#include "Core/EmbeddedAssets.hpp" +#include "Core/Fs.hpp" +#include +#include +#include +namespace emerald::core::embedded { +namespace { +constexpr std::array decode_table() { + std::array table{}; + for (std::int8_t &value : table) { + value = -1; + } + constexpr char kAlphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (std::int8_t i = 0; i < 64; ++i) { + table[static_cast(kAlphabet[i])] = i; + } + return table; +} +constexpr std::array kDecode = decode_table(); +std::vector decode(std::string_view text, + std::size_t size_hint) { + std::vector bytes; + bytes.reserve(size_hint); + int buffer = 0; + int bits = 0; + for (const char ch : text) { + const int value = kDecode[static_cast(ch)]; + if (value < 0) { + continue; + } + buffer = (buffer << 6) | value; + bits += 6; + if (bits >= 8) { + bits -= 8; + bytes.push_back(static_cast((buffer >> bits) & 0xFF)); + } + } + return bytes; +} +} // namespace + +std::string_view build_id() { return detail::kBuildId; } +bool is_extracted(const std::filesystem::path &root) { + const std::optional marker = read_file(root / ".complete"); + return marker.has_value() && *marker == std::string(build_id()); +} + +bool extract_to(const std::filesystem::path &root) { + for (unsigned long long i = 0; i < detail::kFileCount; ++i) { + const RawFile &file = detail::kFiles[i]; + const std::vector bytes = + decode(file.data, static_cast(file.size)); + const std::string_view contents( + reinterpret_cast(bytes.data()), bytes.size()); + if (!write_file(root / file.path, contents)) { + return false; + } + } + return write_file(root / ".complete", build_id()); +} +} // namespace emerald::core::embedded diff --git a/src/Core/EmbeddedAssets.hpp b/src/Core/EmbeddedAssets.hpp new file mode 100644 index 0000000..646f1b6 --- /dev/null +++ b/src/Core/EmbeddedAssets.hpp @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include +namespace emerald::core::embedded { +struct RawFile { + const char *path; + const char *data; + unsigned long long size; +}; +namespace detail { +extern const char kBuildId[]; +extern const unsigned long long kFileCount; +extern const RawFile kFiles[]; +} // namespace detail + +std::string_view build_id(); +bool is_extracted(const std::filesystem::path &root); +bool extract_to(const std::filesystem::path &root); +} // namespace emerald::core::embedded diff --git a/src/Core/Fs.cpp b/src/Core/Fs.cpp new file mode 100644 index 0000000..8c81d07 --- /dev/null +++ b/src/Core/Fs.cpp @@ -0,0 +1,109 @@ +#include "Core/Fs.hpp" +#include +#include +namespace emerald::core { +namespace { +std::filesystem::path temp_sibling_path(const std::filesystem::path &path) { + std::filesystem::path temp = path; + temp += ".tmp"; + return temp; +} +} // namespace + +bool file_exists(const std::filesystem::path &path) { + std::error_code error; + return std::filesystem::is_regular_file(path, error); +} + +bool ensure_directory(const std::filesystem::path &path) { + if (path.empty()) { + return false; + } + std::error_code error; + std::filesystem::create_directories(path, error); + return std::filesystem::is_directory(path, error); +} + +std::optional read_file(const std::filesystem::path &path) { + std::ifstream stream{path, std::ios::binary}; + if (!stream) { + return std::nullopt; + } + std::string contents; + stream.seekg(0, std::ios::end); + const std::streamoff size = stream.tellg(); + if (size > 0) { + contents.resize(static_cast(size)); + stream.seekg(0, std::ios::beg); + stream.read(contents.data(), size); + } + return contents; +} + +bool write_file(const std::filesystem::path &path, std::string_view contents) { + if (path.has_parent_path() && !ensure_directory(path.parent_path())) { + return false; + } + std::ofstream stream{path, std::ios::binary | std::ios::trunc}; + if (!stream) { + return false; + } + stream.write(contents.data(), static_cast(contents.size())); + return static_cast(stream); +} + +bool write_file_atomic(const std::filesystem::path &path, + std::string_view contents) { + const std::filesystem::path temp = temp_sibling_path(path); + if (!write_file(temp, contents)) { + return false; + } + std::error_code error; + std::filesystem::rename(temp, path, error); + if (error) { + std::filesystem::remove(temp, error); + return false; + } + return true; +} + +bool copy_file(const std::filesystem::path &from, + const std::filesystem::path &to) { + std::error_code error; + if (!ensure_directory(to.parent_path())) { + return false; + } + std::filesystem::copy_file( + from, to, std::filesystem::copy_options::overwrite_existing, error); + return !error; +} + +bool copy_directory(const std::filesystem::path &from, + const std::filesystem::path &to) { + std::error_code error; + std::filesystem::create_directories(to, error); + if (error) { + return false; + } + for (const std::filesystem::directory_entry &entry : + std::filesystem::directory_iterator(from, error)) { + if (error) { + return false; + } + const std::filesystem::path target = to / entry.path().filename(); + if (entry.is_directory()) { + if (!copy_directory(entry.path(), target)) { + return false; + } + } else { + std::filesystem::copy_file( + entry.path(), target, + std::filesystem::copy_options::overwrite_existing, error); + if (error) { + return false; + } + } + } + return true; +} +} // namespace emerald::core diff --git a/src/Core/Fs.hpp b/src/Core/Fs.hpp new file mode 100644 index 0000000..0b40488 --- /dev/null +++ b/src/Core/Fs.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include +#include +namespace emerald::core { +bool file_exists(const std::filesystem::path &path); +bool ensure_directory(const std::filesystem::path &path); +std::optional read_file(const std::filesystem::path &path); +bool write_file(const std::filesystem::path &path, std::string_view contents); +bool write_file_atomic(const std::filesystem::path &path, + std::string_view contents); +bool copy_directory(const std::filesystem::path &from, + const std::filesystem::path &to); +bool copy_file(const std::filesystem::path &from, + const std::filesystem::path &to); +} // namespace emerald::core diff --git a/src/Core/Json.hpp b/src/Core/Json.hpp new file mode 100644 index 0000000..d65b53d --- /dev/null +++ b/src/Core/Json.hpp @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include +namespace emerald { +using Json = nlohmann::json; +template +std::optional json_optional(const Json &object, const char *key) { + if (!object.is_object()) { + return std::nullopt; + } + const auto iterator = object.find(key); + if (iterator == object.end() || iterator->is_null()) { + return std::nullopt; + } + return iterator->get(); +} + +template +void json_set(Json &object, const char *key, const std::optional &value) { + if (value.has_value()) { + object[key] = *value; + } else { + object[key] = nullptr; + } +} + +inline void json_set(Json &object, const char *key, + const std::optional &value) { + if (value.has_value()) { + object[key] = *value; + } else { + object[key] = nullptr; + } +} + +} // namespace emerald diff --git a/src/Core/Log.cpp b/src/Core/Log.cpp new file mode 100644 index 0000000..6a82ad5 --- /dev/null +++ b/src/Core/Log.cpp @@ -0,0 +1,30 @@ +#include "Core/Log.hpp" +#include +namespace emerald::core { +namespace { +SDL_LogPriority to_sdl_priority(LogLevel level) { + switch (level) { + case LogLevel::Debug: + return SDL_LOG_PRIORITY_DEBUG; + case LogLevel::Info: + return SDL_LOG_PRIORITY_INFO; + case LogLevel::Warn: + return SDL_LOG_PRIORITY_WARN; + case LogLevel::Error: + return SDL_LOG_PRIORITY_ERROR; + } + return SDL_LOG_PRIORITY_INFO; +} + +} // namespace + +void log(LogLevel level, std::string_view message) { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, to_sdl_priority(level), "%.*s", + static_cast(message.size()), message.data()); +} + +void debug(std::string_view message) { log(LogLevel::Debug, message); } +void info(std::string_view message) { log(LogLevel::Info, message); } +void warn(std::string_view message) { log(LogLevel::Warn, message); } +void error(std::string_view message) { log(LogLevel::Error, message); } +} // namespace emerald::core diff --git a/src/Core/Log.hpp b/src/Core/Log.hpp new file mode 100644 index 0000000..ced390c --- /dev/null +++ b/src/Core/Log.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +namespace emerald::core { +enum class LogLevel { + Debug, + Info, + Warn, + Error, +}; + +void log(LogLevel level, std::string_view message); +void debug(std::string_view message); +void info(std::string_view message); +void warn(std::string_view message); +void error(std::string_view message); + +} // namespace emerald::core diff --git a/src/Core/Paths.cpp b/src/Core/Paths.cpp new file mode 100644 index 0000000..7a3f73b --- /dev/null +++ b/src/Core/Paths.cpp @@ -0,0 +1,87 @@ +#include "Core/Paths.hpp" +#include +#include +#include +#include +#include +namespace emerald::core { +namespace { +constexpr std::string_view kAppIdentifier = "com.emerald.legacy"; +std::optional env_path(const char *name) { + const char *value = std::getenv(name); + if (value == nullptr || value[0] == '\0') { + return std::nullopt; + } + return std::filesystem::path{value}; +} + +std::filesystem::path home_dir() { + if (auto home = env_path("HOME")) { + return *home; + } +#if defined(_WIN32) + if (auto profile = env_path("USERPROFILE")) { + return *profile; + } +#endif + return {}; +} + +std::filesystem::path base_data_dir() { +#if defined(_WIN32) + if (auto local = env_path("LOCALAPPDATA")) { + return *local; + } + if (auto roaming = env_path("APPDATA")) { + return *roaming; + } + return executable_dir(); +#elif defined(__APPLE__) + return home_dir() / "Library" / "Application Support"; +#else + if (auto xdg = env_path("XDG_DATA_HOME")) { + return *xdg; + } + return home_dir() / ".local" / "share"; +#endif +} +} // namespace + +std::filesystem::path app_data_dir() { + return base_data_dir() / std::string{kAppIdentifier}; +} + +std::filesystem::path config_file_path() { + return app_data_dir() / "emerald_legacy_config.json"; +} + +std::filesystem::path playtime_file_path() { + return app_data_dir() / "playtime.json"; +} + +std::filesystem::path state_file_path() { + return app_data_dir() / "state.json"; +} + +std::filesystem::path instances_dir() { return app_data_dir() / "instances"; } +std::filesystem::path local_storage_dir() { + return app_data_dir() / "localstorage"; +} + +std::filesystem::path webkit_website_data_dir() { +#if defined(__APPLE__) + return home_dir() / "Library" / "WebKit" / std::string{kAppIdentifier} / + "WebsiteData"; +#else + return local_storage_dir(); +#endif +} + +std::filesystem::path executable_dir() { + const char *raw = SDL_GetBasePath(); + if (raw == nullptr) { + return std::filesystem::current_path(); + } + return std::filesystem::path{raw}; +} +} // namespace emerald::core diff --git a/src/Core/Paths.hpp b/src/Core/Paths.hpp new file mode 100644 index 0000000..c6b997d --- /dev/null +++ b/src/Core/Paths.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +namespace emerald::core { +std::filesystem::path app_data_dir(); +std::filesystem::path config_file_path(); +std::filesystem::path playtime_file_path(); +std::filesystem::path state_file_path(); +std::filesystem::path instances_dir(); +std::filesystem::path executable_dir(); +std::filesystem::path local_storage_dir(); +std::filesystem::path webkit_website_data_dir(); +} // namespace emerald::core diff --git a/src/Instances/ArgsSchema.cpp b/src/Instances/ArgsSchema.cpp new file mode 100644 index 0000000..4caacf5 --- /dev/null +++ b/src/Instances/ArgsSchema.cpp @@ -0,0 +1,509 @@ +#include "Instances/ArgsSchema.hpp" +#include +#include +#include +#include +namespace emerald::instances { +namespace { +constexpr std::string_view kValidTypes[] = {"boolean", "int", "number", + "string", "choice"}; +bool is_string_attr(const Json &object, const char *key) { + const auto found = object.find(key); + return found != object.end() && found->is_string() && + !found->get().empty(); +} + +std::optional option_type(const std::string &type) { + if (type == "boolean") { + return OptionType::Boolean; + } + if (type == "int") { + return OptionType::Int; + } + if (type == "number") { + return OptionType::Number; + } + if (type == "string") { + return OptionType::String; + } + if (type == "choice") { + return OptionType::Choice; + } + return std::nullopt; +} + +bool is_finite_number(const Json &value) { + return value.is_number() && std::isfinite(value.get()); +} + +std::optional finite_number_attr(const Json &object, const char *key) { + const auto found = object.find(key); + if (found == object.end() || !is_finite_number(*found)) { + return std::nullopt; + } + return found->get(); +} + +bool is_valid_condition(const Json &cond); +bool is_valid_leaf(const Json &cond) { + if (!is_string_attr(cond, "option")) { + return false; + } + return cond.contains("equals") || cond.contains("in") || + cond.contains("not") || cond.contains("exists"); +} + +bool is_valid_condition(const Json &cond) { + if (!cond.is_object()) { + return false; + } + if (cond.contains("all")) { + if (!cond["all"].is_array() || cond["all"].empty()) { + return false; + } + for (const Json &item : cond["all"]) { + if (!is_valid_condition(item)) { + return false; + } + } + } else if (cond.contains("any")) { + if (!cond["any"].is_array() || cond["any"].empty()) { + return false; + } + for (const Json &item : cond["any"]) { + if (!is_valid_condition(item)) { + return false; + } + } + } else if (cond.contains("not")) { + if (!is_valid_condition(cond["not"])) { + return false; + } + } else if (!is_valid_leaf(cond)) { + return false; + } + return true; +} + +bool json_equal(const Json &left, const Json &right) { + if (left.is_number() && right.is_number()) { + return left.get() == right.get(); + } + return left == right; +} + +bool exists_truthy(const Json *value) { + if (value == nullptr || value->is_null()) { + return false; + } + if (value->is_string()) { + return !value->get().empty(); + } + if (value->is_boolean()) { + return value->get(); + } + return true; +} + +bool is_choice_value(const SchemaOption &option, const std::string &value) { + return std::any_of( + option.choices.begin(), option.choices.end(), + [&](const SchemaChoice &choice) { return choice.value == value; }); +} + +std::string number_text(const Json &value, bool) { + std::array buffer{}; + const auto result = + std::to_chars(buffer.data(), buffer.data() + buffer.size(), + value.get(), std::chars_format::general); + return std::string(buffer.data(), result.ptr); +} +} // namespace + +std::optional parse_schema(const std::string &raw) { + Json parsed; + try { + parsed = Json::parse(raw); + } catch (const Json::parse_error &) { + return std::nullopt; + } + if (!parsed.is_object() || !parsed.contains("$schema") || + !parsed["options"].is_array()) { + return std::nullopt; + } + + ArgsSchema schema; + schema.schema = "$schema"; + if (parsed.contains("meta") && parsed["meta"].is_object()) { + const Json &meta = parsed["meta"]; + if (meta.contains("name") && meta["name"].is_string()) { + schema.meta_name = meta["name"].get(); + } + if (meta.contains("description") && meta["description"].is_string()) { + schema.meta_description = meta["description"].get(); + } + } + + std::vector group_ids; + for (const Json &item : parsed.value("groups", Json::array())) { + if (!item.is_object() || !is_string_attr(item, "id")) { + continue; + } + SchemaGroup group; + group.id = item["id"].get(); + group.title = item.value("title", group.id); + group.description = + item.contains("description") && item["description"].is_string() + ? std::optional(item["description"].get()) + : std::nullopt; + if (std::find(group_ids.begin(), group_ids.end(), group.id) != + group_ids.end()) { + continue; + } + group_ids.push_back(group.id); + schema.groups.push_back(std::move(group)); + } + + std::vector option_ids; + for (const Json &item : parsed["options"]) { + if (!item.is_object() || !is_string_attr(item, "id") || + !is_string_attr(item, "title") || !is_string_attr(item, "arg")) { + continue; + } + const std::string id = item["id"].get(); + const std::string type_name = item.value("type", ""); + if (!is_string_attr(item, "type") || !option_type(type_name).has_value()) { + continue; + } + if (std::find(option_ids.begin(), option_ids.end(), id) != + option_ids.end()) { + continue; + } + + SchemaOption option; + option.id = id; + option.title = item["title"].get(); + option.arg = item["arg"].get(); + option.type = *option_type(type_name); + option.default_value = json_optional(item, "default"); + const OptionType type = option.type; + if (type == OptionType::Choice) { + if (!item["choices"].is_array() || item["choices"].empty()) { + continue; + } + std::vector choice_values; + bool valid_choices = true; + for (const Json &choice : item["choices"]) { + if (!choice.is_object() || !is_string_attr(choice, "value")) { + valid_choices = false; + break; + } + const std::string value = choice["value"].get(); + if (std::find(choice_values.begin(), choice_values.end(), value) != + choice_values.end()) { + valid_choices = false; + break; + } + choice_values.push_back(value); + SchemaChoice parsed_choice; + parsed_choice.value = value; + parsed_choice.label = + choice.contains("label") && choice["label"].is_string() + ? choice["label"].get() + : value; + option.choices.push_back(std::move(parsed_choice)); + } + if (!valid_choices || option.choices.empty()) { + continue; + } + if (option.default_value.has_value() && + (!option.default_value->is_string() || + !is_choice_value(option, + option.default_value->get()))) { + option.default_value.reset(); + } + } else { + if (option.default_value.has_value()) { + const Json &value = *option.default_value; + const bool ok = + (type == OptionType::Boolean && value.is_boolean()) || + ((type == OptionType::Int || type == OptionType::Number) && + is_finite_number(value)) || + (type == OptionType::String && value.is_string()); + if (!ok) { + option.default_value.reset(); + } + } + } + + option.min = finite_number_attr(item, "min"); + option.max = finite_number_attr(item, "max"); + option.step = finite_number_attr(item, "step"); + option.description = + item.contains("description") && item["description"].is_string() + ? std::optional(item["description"].get()) + : std::nullopt; + option.group = + item.contains("group") && item["group"].is_string() + ? std::optional(item["group"].get()) + : std::nullopt; + option.placeholder = + item.contains("placeholder") && item["placeholder"].is_string() + ? std::optional(item["placeholder"].get()) + : std::nullopt; + + option_ids.push_back(id); + schema.options.push_back(std::move(option)); + } + + if (schema.options.empty()) { + return std::nullopt; + } + + for (const Json &item : parsed.value("dependencies", Json::array())) { + if (!item.is_object() || !is_string_attr(item, "target")) { + continue; + } + const std::string target = item["target"].get(); + if (std::find(option_ids.begin(), option_ids.end(), target) == + option_ids.end()) { + continue; + } + const auto when = item.find("when"); + if (when == item.end() || !is_valid_condition(*when)) { + continue; + } + SchemaDependency dependency; + dependency.target = target; + dependency.when = *when; + dependency.hide = item.value("effect", "disable") == "hide"; + schema.dependencies.push_back(std::move(dependency)); + } + + schema.schema_version = 1; + return schema; +} + +Json option_default(const SchemaOption &option) { + switch (option.type) { + case OptionType::Boolean: + return option.default_value.has_value() && + option.default_value->is_boolean() + ? *option.default_value + : Json(false); + case OptionType::Int: + case OptionType::Number: + if (option.default_value.has_value() && + is_finite_number(*option.default_value)) { + return *option.default_value; + } + return Json(0); + case OptionType::String: + return option.default_value.has_value() && option.default_value->is_string() + ? *option.default_value + : Json(std::string{}); + case OptionType::Choice: + if (option.default_value.has_value() && option.default_value->is_string() && + is_choice_value(option, option.default_value->get())) { + return *option.default_value; + } + if (!option.choices.empty()) { + return Json(option.choices.front().value); + } + return Json(std::string{}); + } + return Json(std::string{}); +} + +Json merge_values(const ArgsSchema &schema, const Json &saved) { + Json merged = Json::object(); + for (const SchemaOption &option : schema.options) { + merged[option.id] = option_default(option); + } + const Json *saved_object = saved.is_object() ? &saved : nullptr; + if (saved_object == nullptr) { + return merged; + } + for (const SchemaOption &option : schema.options) { + const auto found = saved_object->find(option.id); + if (found == saved_object->end()) { + continue; + } + const Json &value = *found; + bool ok = false; + switch (option.type) { + case OptionType::Boolean: + ok = value.is_boolean(); + break; + case OptionType::Int: + case OptionType::Number: + ok = is_finite_number(value); + break; + case OptionType::String: + ok = value.is_string(); + break; + case OptionType::Choice: + ok = value.is_string() && + is_choice_value(option, value.get()); + break; + } + if (ok) { + merged[option.id] = value; + } + } + return merged; +} + +namespace { +bool evaluate_condition(const Json &cond, const Json &values); +bool evaluate_leaf(const Json &cond, const Json &values) { + const std::string option = cond["option"].get(); + const auto found = values.find(option); + if (cond.contains("equals")) { + return found != values.end() && json_equal(*found, cond["equals"]); + } + if (cond.contains("in")) { + if (!cond["in"].is_array() || found == values.end()) { + return false; + } + for (const Json &candidate : cond["in"]) { + if (json_equal(*found, candidate)) { + return true; + } + } + return false; + } + if (cond.contains("not")) { + return found == values.end() || !json_equal(*found, cond["not"]); + } + if (cond.contains("exists")) { + const bool expect_true = cond["exists"].get(); + return expect_true + ? exists_truthy(found != values.end() ? &(*found) : nullptr) + : !exists_truthy(found != values.end() ? &(*found) : nullptr); + } + return false; +} + +bool evaluate_condition(const Json &cond, const Json &values) { + if (!cond.is_object()) { + return false; + } + if (cond.contains("all")) { + const Json &entries = cond["all"]; + return std::all_of(entries.begin(), entries.end(), [&](const Json &item) { + return evaluate_condition(item, values); + }); + } + if (cond.contains("any")) { + const Json &entries = cond["any"]; + return std::any_of(entries.begin(), entries.end(), [&](const Json &item) { + return evaluate_condition(item, values); + }); + } + if (cond.contains("not")) { + return !evaluate_condition(cond["not"], values); + } + return evaluate_leaf(cond, values); +} +} // namespace + +std::map compute_effects(const ArgsSchema &schema, + const Json &values) { + std::map effects; + for (const SchemaOption &option : schema.options) { + effects[option.id] = OptionEffects{}; + } + for (const SchemaDependency &dependency : schema.dependencies) { + if (!evaluate_condition(dependency.when, values)) { + continue; + } + OptionEffects &effect = effects[dependency.target]; + effect.disabled = true; + if (dependency.hide) { + effect.hidden = true; + } + } + return effects; +} + +std::vector +build_args(const ArgsSchema &schema, const Json &values, + const std::map &effects) { + std::vector args; + for (const SchemaOption &option : schema.options) { + const auto effect = effects.find(option.id); + if (effect != effects.end() && + (effect->second.hidden || effect->second.disabled)) { + continue; + } + const auto found = values.find(option.id); + if (found == values.end()) { + continue; + } + const Json &value = *found; + switch (option.type) { + case OptionType::Boolean: + if (value.is_boolean() && value.get()) { + args.push_back(option.arg); + } + break; + case OptionType::Int: + if (is_finite_number(value)) { + args.push_back(option.arg); + args.push_back(number_text(value, true)); + } + break; + case OptionType::Number: + if (is_finite_number(value)) { + args.push_back(option.arg); + args.push_back(number_text(value, false)); + } + break; + case OptionType::String: + if (value.is_string()) { + const std::string &text = value.get_ref(); + if (!text.empty()) { + args.push_back(option.arg); + args.push_back(text); + } + } + break; + case OptionType::Choice: + if (value.is_string() && !value.get().empty()) { + args.push_back(option.arg); + args.push_back(value.get()); + } + break; + } + } + return args; +} + +std::string display_value(const SchemaOption &option, const Json &value) { + switch (option.type) { + case OptionType::Boolean: + return value.is_boolean() ? (value.get() ? "true" : "false") + : std::string{}; + case OptionType::Int: + return is_finite_number(value) ? number_text(value, true) : std::string{}; + case OptionType::Number: + return is_finite_number(value) ? number_text(value, false) : std::string{}; + case OptionType::String: + return value.is_string() ? value.get() : std::string{}; + case OptionType::Choice: { + if (!value.is_string()) { + return std::string{}; + } + const std::string text = value.get(); + for (const SchemaChoice &choice : option.choices) { + if (choice.value == text) { + return choice.label; + } + } + return text; + } + } + return std::string{}; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/ArgsSchema.hpp b/src/Instances/ArgsSchema.hpp new file mode 100644 index 0000000..cdf4b92 --- /dev/null +++ b/src/Instances/ArgsSchema.hpp @@ -0,0 +1,72 @@ +#pragma once +#include "Core/Json.hpp" +#include +#include +#include +#include +namespace emerald::instances { +enum class OptionType { + Boolean, + Int, + Number, + String, + Choice, +}; + +struct SchemaChoice { + std::string value; + std::string label; +}; + +struct SchemaOption { + std::string id; + std::string title; + std::string arg; + OptionType type = OptionType::String; + std::optional description; + std::optional group; + std::optional default_value; + std::optional min; + std::optional max; + std::optional step; + std::optional placeholder; + std::vector choices; +}; + +struct SchemaGroup { + std::string id; + std::string title; + std::optional description; +}; + +struct SchemaDependency { + std::string target; + Json when; + bool hide = false; +}; + +struct ArgsSchema { + std::string schema; + int schema_version = 1; + std::optional meta_name; + std::optional meta_description; + std::vector groups; + std::vector options; + std::vector dependencies; +}; + +struct OptionEffects { + bool hidden = false; + bool disabled = false; +}; + +std::optional parse_schema(const std::string &raw); +Json option_default(const SchemaOption &option); +Json merge_values(const ArgsSchema &schema, const Json &saved); +std::map compute_effects(const ArgsSchema &schema, + const Json &values); +std::vector +build_args(const ArgsSchema &schema, const Json &values, + const std::map &effects); +std::string display_value(const SchemaOption &option, const Json &value); +} // namespace emerald::instances diff --git a/src/Instances/Backup.cpp b/src/Instances/Backup.cpp new file mode 100644 index 0000000..c588420 --- /dev/null +++ b/src/Instances/Backup.cpp @@ -0,0 +1,208 @@ +#include "Instances/Backup.hpp" +#include "Core/Fs.hpp" +#include "Instances/Installer.hpp" +#include "Instances/InstanceManager.hpp" +#include +#include +#include +#include +#include +namespace emerald::instances { +namespace { +bool write_file_data(struct archive *output, const std::filesystem::path &path, + std::string &error) { + std::FILE *source = std::fopen(path.string().c_str(), "rb"); + if (source == nullptr) { + error = "Failed to read " + path.string(); + return false; + } + + std::vector buffer(64 * 1024); + while (true) { + const std::size_t read = + std::fread(buffer.data(), 1, buffer.size(), source); + if (read == 0) { + break; + } + if (archive_write_data(output, buffer.data(), read) < 0) { + std::fprintf(stderr, "backup: %s\n", archive_error_string(output)); + std::fclose(source); + error = "Failed to write archive data"; + return false; + } + } + std::fclose(source); + return true; +} + +bool write_entry(struct archive *output, const std::filesystem::path &path, + const std::string &archive_path, std::string &error) { + struct archive_entry *entry = archive_entry_new(); + archive_entry_set_pathname(entry, archive_path.c_str()); + std::error_code error_code; + if (std::filesystem::is_symlink(path, error_code)) { + const std::filesystem::path target = + std::filesystem::read_symlink(path, error_code); + if (error_code) { + archive_entry_free(entry); + error = "Failed to read symlink " + path.string(); + return false; + } + archive_entry_set_filetype(entry, AE_IFLNK); + archive_entry_set_symlink(entry, target.string().c_str()); + archive_entry_set_perm(entry, 0777); + archive_entry_set_size(entry, 0); + if (archive_write_header(output, entry) != ARCHIVE_OK) { + archive_entry_free(entry); + error = "Failed to write symlink entry"; + return false; + } + archive_entry_free(entry); + return true; + } + + if (std::filesystem::is_directory(path, error_code)) { + archive_entry_set_filetype(entry, AE_IFDIR); + archive_entry_set_perm(entry, 0755); + if (archive_write_header(output, entry) != ARCHIVE_OK) { + archive_entry_free(entry); + error = "Failed to write directory entry"; + return false; + } + archive_entry_free(entry); + return true; + } + + const std::size_t size = + static_cast(std::filesystem::file_size(path, error_code)); + if (error_code) { + archive_entry_free(entry); + error = "Failed to stat " + path.string(); + return false; + } + + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_entry_set_size(entry, static_cast(size)); + if (archive_write_header(output, entry) != ARCHIVE_OK) { + archive_entry_free(entry); + error = "Failed to write file entry"; + return false; + } + archive_entry_free(entry); + + if (size == 0) { + return true; + } + return write_file_data(output, path, error); +} + +bool write_recursive(struct archive *output, + const std::filesystem::path ¤t, + const std::filesystem::path &root, + const std::string &prefix, std::string &error) { + std::error_code error_code; + std::filesystem::directory_iterator it(current, error_code); + if (error_code) { + error = "Failed to read directory " + current.string(); + return false; + } + + std::vector children; + for (const std::filesystem::directory_entry &entry : it) { + children.push_back(entry.path()); + } + std::sort(children.begin(), children.end()); + for (const std::filesystem::path &child : children) { + const std::string name = child.filename().string(); + if (!write_entry(output, child, prefix + "/" + name, error)) { + return false; + } + std::error_code child_error; + if (std::filesystem::is_directory(child, child_error) && + !std::filesystem::is_symlink(child, child_error)) { + if (!write_recursive(output, child, root, prefix + "/" + name, error)) { + return false; + } + } + } + return true; +} +} // namespace + +bool create_instance_backup(const std::filesystem::path &instance_dir, + const std::filesystem::path &destination, + std::string &error) { + std::error_code error_code; + if (!std::filesystem::is_directory(instance_dir, error_code)) { + error = "Instance not found"; + return false; + } + if (!core::ensure_directory(destination.parent_path())) { + error = "Failed to create backup directory"; + return false; + } + + struct archive *output = archive_write_new(); + archive_write_add_filter_gzip(output); + archive_write_set_format_pax_restricted(output); + if (archive_write_open_filename(output, destination.string().c_str()) != + ARCHIVE_OK) { + error = "Failed to create backup"; + archive_write_free(output); + return false; + } + + const std::string prefix = instance_dir.filename().string(); + if (prefix.empty()) { + error = "Invalid dir name"; + archive_write_free(output); + return false; + } + + bool ok = write_entry(output, instance_dir, prefix, error); + if (ok) { + ok = write_recursive(output, instance_dir, instance_dir, prefix, error); + } + + archive_write_close(output); + archive_write_free(output); + return ok; +} + +std::optional +restore_instance_backup(const std::filesystem::path &archive, + const std::filesystem::path &instances_dir, + std::string &error) { + if (!core::ensure_directory(instances_dir)) { + error = "Failed to create instances directory"; + return std::nullopt; + } + + std::string extract_error; + if (!extract_archive(archive, instances_dir, extract_error)) { + error = "Failed to extract backup: " + extract_error; + return std::nullopt; + } + + std::error_code error_code; + std::filesystem::directory_iterator it(instances_dir, error_code); + if (!error_code) { + std::vector candidates; + for (const std::filesystem::directory_entry &entry : it) { + if (!entry.is_directory(error_code)) { + continue; + } + candidates.push_back(entry.path()); + } + std::sort(candidates.begin(), candidates.end()); + for (const std::filesystem::path &candidate : candidates) { + if (std::filesystem::exists(candidate / std::string(kExecutableMarker), + error_code)) { + return candidate.filename().string(); + } + } + } + return std::string("restored"); +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Backup.hpp b/src/Instances/Backup.hpp new file mode 100644 index 0000000..86372f3 --- /dev/null +++ b/src/Instances/Backup.hpp @@ -0,0 +1,15 @@ +#pragma once +#include +#include +#include +namespace emerald::instances { +bool create_instance_backup(const std::filesystem::path &instance_dir, + const std::filesystem::path &destination, + std::string &error); + +std::optional +restore_instance_backup(const std::filesystem::path &archive, + const std::filesystem::path &instances_dir, + std::string &error); + +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Dlc.cpp b/src/Instances/Dlc.cpp new file mode 100644 index 0000000..581dfea --- /dev/null +++ b/src/Instances/Dlc.cpp @@ -0,0 +1,270 @@ +#include "Instances/Dlc.hpp" +#include "Core/Fs.hpp" +#include "Core/Json.hpp" +namespace emerald::instances { +namespace { +std::vector path_segments(const std::string &path) { + std::vector segments; + std::size_t start = 0; + while (start <= path.size()) { + const std::size_t slash = path.find('/', start); + const std::string piece = path.substr( + start, slash == std::string::npos ? std::string::npos : slash - start); + if (!piece.empty()) { + segments.push_back(piece); + } + if (slash == std::string::npos) { + break; + } + start = slash + 1; + } + return segments; +} + +bool parse_json_entries(const Json &json, std::vector &out) { + if (!json.is_array()) { + return false; + } + for (const Json &item : json) { + const std::optional name = + json_optional(item, "name"); + const std::optional type = + json_optional(item, "type"); + if (!name.has_value() || !type.has_value()) { + continue; + } + out.push_back(GitEntry{*name, *type == "dir"}); + } + return true; +} + +Json parse_or_null(const std::string &text, std::string &error) { + Json json = Json::object(); + try { + json = Json::parse(text); + } catch (const std::exception &exception) { + error = std::string("Failed to parse response: ") + exception.what(); + } + return json; +} +} // namespace + +bool parse_git_url(const std::string &url, GitRepoRef &out, + std::string &error) { + const std::size_t scheme = url.find("://"); + if (scheme == std::string::npos) { + error = "Invalid URL"; + return false; + } + const std::size_t host_start = scheme + 3; + const std::size_t path_start = url.find('/', host_start); + if (path_start == std::string::npos || path_start == host_start) { + error = "No host in URL"; + return false; + } + + out.host = url.substr(host_start, path_start - host_start); + const std::vector segments = + path_segments(url.substr(path_start)); + if (segments.size() < 2) { + error = "Invalid repo URL: need owner and repo"; + return false; + } + out.owner = segments[0]; + out.repo = segments[1]; + const std::string suffix = ".git"; + if (out.repo.size() > suffix.size() && + out.repo.compare(out.repo.size() - suffix.size(), suffix.size(), + suffix) == 0) { + out.repo = out.repo.substr(0, out.repo.size() - suffix.size()); + } + out.is_github = + out.host == "github.com" || out.host == "raw.githubusercontent.com"; + return true; +} + +std::string git_api_url(const GitRepoRef &ref, const std::string &path, + const std::string &branch) { + std::string api_path; + if (!path.empty() && path != "." && path != "/") { + std::string trimmed = path; + while (!trimmed.empty() && trimmed.front() == '/') { + trimmed.erase(trimmed.begin()); + } + api_path = "/" + trimmed; + } + + if (ref.is_github) { + return "https://api.github.com/repos/" + ref.owner + "/" + ref.repo + + "/contents" + api_path + "?ref=" + branch; + } + return "https://" + ref.host + "/api/v1/repos/" + ref.owner + "/" + ref.repo + + "/contents" + api_path + "?ref=" + branch; +} + +std::string git_raw_url(const GitRepoRef &ref, const std::string &branch, + const std::string &path) { + if (ref.is_github) { + return "https://raw.githubusercontent.com/" + ref.owner + "/" + ref.repo + + "/" + branch + "/" + path; + } + return "https://" + ref.host + "/" + ref.owner + "/" + ref.repo + + "/raw/branch/" + branch + "/" + path; +} + +bool DlcService::list_directory(const std::string &repo_url, + const std::string &branch, + const std::string &path, + std::vector &out, + std::string &error) { + GitRepoRef ref; + if (!parse_git_url(repo_url, ref, error)) { + return false; + } + + const net::HttpResponse response = + client_.get(git_api_url(ref, path, branch)); + if (response.status == 404) { + return true; + } + if (response.status < 200 || response.status >= 300) { + error = "Git API returned " + std::to_string(response.status); + return false; + } + + std::string parse_error; + const Json json = parse_or_null(response.body, parse_error); + if (!parse_error.empty()) { + error = parse_error; + return false; + } + + if (json.is_array()) { + parse_json_entries(json, out); + return true; + } + if (json.is_object()) { + const std::optional type = + json_optional(json, "type"); + if (type.value_or("") != "dir") { + return true; + } + const std::optional sub_path = + json_optional(json, "path"); + return list_directory(repo_url, branch, sub_path.value_or(""), out, error); + } + return true; +} + +bool DlcService::collect_files(const GitRepoRef &ref, const std::string &branch, + const std::string &root_path, + std::vector &out, + std::string &error) { + std::vector pending{root_path}; + while (!pending.empty()) { + const std::string dir = pending.back(); + pending.pop_back(); + const net::HttpResponse response = + client_.get(git_api_url(ref, dir, branch)); + if (response.status < 200 || response.status >= 300) { + error = + "Failed to list " + dir + ": HTTP " + std::to_string(response.status); + return false; + } + + std::string parse_error; + const Json json = parse_or_null(response.body, parse_error); + if (!parse_error.empty()) { + error = parse_error; + return false; + } + + if (!json.is_array()) { + if (!json.is_object()) { + continue; + } + const std::optional type = + json_optional(json, "type"); + if (type.value_or("") == "dir") { + continue; + } + out.push_back(dir); + continue; + } + + for (const Json &entry : json) { + const std::optional name = + json_optional(entry, "name"); + const std::optional type = + json_optional(entry, "type"); + if (!name.has_value() || !type.has_value()) { + continue; + } + const std::string full_path = dir.empty() ? *name : dir + "/" + *name; + if (*type == "dir") { + pending.push_back(full_path); + } else { + out.push_back(full_path); + } + } + } + return true; +} + +bool DlcService::download_folder( + const std::string &instance_id, const std::string &repo_url, + const std::string &branch, const std::string &dlc_folder, + net::CancelToken &token, + const std::function &on_progress, + std::string &error) { + GitRepoRef ref; + if (!parse_git_url(repo_url, ref, error)) { + return false; + } + + std::vector files; + if (!collect_files(ref, branch, dlc_folder, files, error)) { + return false; + } + if (files.empty()) { + error = "No files found in '" + dlc_folder + "' folder"; + return false; + } + + const std::filesystem::path dest = instances_.working_dir(instance_id) / + "Windows64Media" / "DLC" / dlc_folder; + if (!core::ensure_directory(dest)) { + error = "Failed to create DLC directory"; + return false; + } + + const std::string prefix = dlc_folder + "/"; + const double total = static_cast(files.size()); + for (std::size_t index = 0; index < files.size(); ++index) { + const std::string &file_path = files[index]; + std::string relative = file_path; + if (relative.compare(0, prefix.size(), prefix) == 0) { + relative = relative.substr(prefix.size()); + } + + const std::filesystem::path target = dest / relative; + if (!core::ensure_directory(target.parent_path())) { + error = "Failed to create directory for " + file_path; + return false; + } + + std::optional last_modified; + std::string download_error; + if (!client_.download(git_raw_url(ref, branch, file_path), target, token, + nullptr, last_modified, download_error)) { + error = "Failed to download " + file_path + ": " + download_error; + return false; + } + + if (on_progress) { + on_progress((static_cast(index) + 1.0) / total * 100.0); + } + } + return true; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Dlc.hpp b/src/Instances/Dlc.hpp new file mode 100644 index 0000000..e004d5e --- /dev/null +++ b/src/Instances/Dlc.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "Instances/InstanceManager.hpp" +#include "Net/HttpClient.hpp" +#include +#include +#include +#include +#include +namespace emerald::instances { +struct GitEntry { + std::string name; + bool is_dir = false; +}; + +struct GitRepoRef { + std::string owner; + std::string repo; + std::string host; + bool is_github = false; +}; + +bool parse_git_url(const std::string &url, GitRepoRef &out, std::string &error); +std::string git_api_url(const GitRepoRef &ref, const std::string &path, + const std::string &branch); +std::string git_raw_url(const GitRepoRef &ref, const std::string &branch, + const std::string &path); + +class DlcService { +public: + DlcService(const InstanceManager &instances, net::HttpClient &client) + : instances_(instances), client_(client) {} + + bool list_directory(const std::string &repo_url, const std::string &branch, + const std::string &path, std::vector &out, + std::string &error); + + bool download_folder(const std::string &instance_id, + const std::string &repo_url, const std::string &branch, + const std::string &dlc_folder, net::CancelToken &token, + const std::function &on_progress, + std::string &error); + +private: + bool collect_files(const GitRepoRef &ref, const std::string &branch, + const std::string &root_path, + std::vector &out, std::string &error); + + const InstanceManager &instances_; + net::HttpClient &client_; +}; +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/DownloadManager.cpp b/src/Instances/DownloadManager.cpp new file mode 100644 index 0000000..d21a986 --- /dev/null +++ b/src/Instances/DownloadManager.cpp @@ -0,0 +1,189 @@ +#include "Instances/DownloadManager.hpp" +#include "Core/Log.hpp" +#include "Instances/Installer.hpp" +#include "Instances/InstanceSync.hpp" +#include +namespace emerald::instances { +struct DownloadManager::Job { + net::CancelToken token; + std::atomic finished{false}; + std::thread worker; + DownloadSnapshot snapshot; +}; + +DownloadManager::~DownloadManager() { shutdown(); } +void DownloadManager::shutdown() { + std::map> jobs; + { + std::lock_guard lock(mutex_); + jobs.swap(jobs_); + } + for (auto &[id, job] : jobs) { + job->token.cancel(); + } + for (auto &[id, job] : jobs) { + if (job->worker.joinable()) { + job->worker.join(); + } + } +} + +uint64_t DownloadManager::revision() const { + std::lock_guard lock(mutex_); + return revision_; +} + +bool DownloadManager::start(const DownloadRequest &request) { + if (request.instance_id.empty() || request.url.empty()) { + return false; + } + + auto job = std::make_shared(); + job->snapshot.state = DownloadState::running; + job->snapshot.message = ""; + std::shared_ptr previous; + { + std::lock_guard lock(mutex_); + const auto existing = jobs_.find(request.instance_id); + if (existing != jobs_.end()) { + if (!existing->second->finished.load()) { + return false; + } + previous = existing->second; + } + jobs_[request.instance_id] = job; + ++revision_; + } + if (previous != nullptr && previous->worker.joinable()) { + previous->worker.join(); + } + + DownloadManager *self = this; + job->worker = std::thread([self, job, request] { + core::info("download: start " + request.instance_id + " <- " + + request.url); + net::HttpClient client(request.proxy); + net::CancelToken &token = job->token; + DownloadSnapshot snapshot; + snapshot.state = DownloadState::running; + int log_step = -1; + const DownloadStatus status = install_instance_archive( + client, request.url, request.instance_dir, request.archive_dir, token, + [&](double percent) { + snapshot.percent = percent; + const int step = static_cast(percent) / 5; + if (step != log_step) { + log_step = step; + core::info(" " + request.instance_id + " " + + std::to_string(static_cast(percent)) + "%"); + } + self->touch(request.instance_id, snapshot); + }); + + if (!status.ok) { + if (status.cancelled) { + snapshot.state = DownloadState::cancelled; + snapshot.message = "CANCELLED"; + core::info(" " + request.instance_id + " cancelled"); + } else { + snapshot.state = DownloadState::failed; + snapshot.message = status.error; + core::warn(" " + request.instance_id + " failed: " + status.error); + } + self->finish(request.instance_id, snapshot); + return; + } + + snapshot.state = DownloadState::finished; + snapshot.percent = 100.0; + snapshot.message = "Installed"; + core::info(" " + request.instance_id + " installed"); + self->finish(request.instance_id, snapshot); + sync_instance(request.instance_dir, request.username, request.dlc_source, + request.skin_pck); + }); + + return true; +} + +void DownloadManager::touch(const std::string &instance_id, + const DownloadSnapshot &snapshot) { + std::lock_guard lock(mutex_); + const auto found = jobs_.find(instance_id); + if (found == jobs_.end()) { + return; + } + found->second->snapshot = snapshot; + ++revision_; +} + +void DownloadManager::finish(const std::string &instance_id, + const DownloadSnapshot &snapshot) { + std::lock_guard lock(mutex_); + const auto found = jobs_.find(instance_id); + if (found == jobs_.end()) { + return; + } + found->second->snapshot = snapshot; + found->second->finished.store(true); + ++revision_; +} + +void DownloadManager::cancel(const std::string &instance_id) { + std::shared_ptr job; + { + std::lock_guard lock(mutex_); + const auto found = jobs_.find(instance_id); + if (found == jobs_.end()) { + return; + } + job = found->second; + } + job->token.cancel(); +} + +void DownloadManager::clear(const std::string &instance_id) { + std::shared_ptr job; + { + std::lock_guard lock(mutex_); + const auto found = jobs_.find(instance_id); + if (found == jobs_.end()) { + return; + } + if (!found->second->finished.load()) { + return; + } + job = found->second; + jobs_.erase(found); + ++revision_; + } + if (job->worker.joinable()) { + job->worker.join(); + } +} + +DownloadSnapshot +DownloadManager::snapshot(const std::string &instance_id) const { + std::lock_guard lock(mutex_); + const auto found = jobs_.find(instance_id); + if (found == jobs_.end()) { + return DownloadSnapshot{}; + } + return found->second->snapshot; +} + +bool DownloadManager::is_active(const std::string &instance_id) const { + return snapshot(instance_id).active(); +} + +std::vector DownloadManager::active_ids() const { + std::lock_guard lock(mutex_); + std::vector ids; + for (const auto &[id, job] : jobs_) { + if (!job->finished.load() && job->snapshot.active()) { + ids.push_back(id); + } + } + return ids; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/DownloadManager.hpp b/src/Instances/DownloadManager.hpp new file mode 100644 index 0000000..335230e --- /dev/null +++ b/src/Instances/DownloadManager.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "Net/HttpClient.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +namespace emerald::instances { +enum class DownloadState { + idle, + running, + finished, + cancelled, + failed, +}; + +struct DownloadSnapshot { + DownloadState state = DownloadState::idle; + double percent = 0.0; + int retry_attempt = 0; + std::string message; + bool active() const { return state == DownloadState::running; } +}; + +struct DownloadRequest { + std::string instance_id; + std::string url; + std::filesystem::path instance_dir; + std::filesystem::path archive_dir; + std::optional proxy; + std::string username; + std::filesystem::path dlc_source; + std::filesystem::path skin_pck; +}; + +class DownloadManager { +public: + DownloadManager() = default; + ~DownloadManager(); + DownloadManager(const DownloadManager &) = delete; + DownloadManager &operator=(const DownloadManager &) = delete; + bool start(const DownloadRequest &request); + void cancel(const std::string &instance_id); + void clear(const std::string &instance_id); + DownloadSnapshot snapshot(const std::string &instance_id) const; + bool is_active(const std::string &instance_id) const; + std::vector active_ids() const; + uint64_t revision() const; + void shutdown(); + +private: + struct Job; + void touch(const std::string &instance_id, const DownloadSnapshot &snapshot); + void finish(const std::string &instance_id, const DownloadSnapshot &snapshot); + mutable std::mutex mutex_; + std::map> jobs_; + uint64_t revision_ = 0; +}; +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Downloader.cpp b/src/Instances/Downloader.cpp new file mode 100644 index 0000000..ae623cc --- /dev/null +++ b/src/Instances/Downloader.cpp @@ -0,0 +1,93 @@ +#include "Instances/Downloader.hpp" +#include "Core/Fs.hpp" +#include +#include +namespace emerald::instances { +namespace { +int backoff_seconds(int attempt) { + const int exponent = attempt > 2 ? attempt - 2 : 0; + return 1 << exponent; +} +} // namespace + +DownloadStatus download_file( + net::HttpClient &client, const std::string &url, + const std::filesystem::path &dest, net::CancelToken &token, + const std::function &on_progress, + const std::function &on_retry, + int max_retries) { + DownloadStatus status; + int attempt = 0; + while (attempt < max_retries) { + if (!attempt || !status.cancelled) { + std::optional last_modified; + std::string error; + bool ok = false; + if (attempt > 0) { + std::this_thread::sleep_for( + std::chrono::seconds(backoff_seconds(attempt))); + } + if (token.cancelled()) { + status.cancelled = true; + break; + } + std::function progress; + if (on_progress) { + progress = [on_progress](double total, double now) { + if (total > 0) { + on_progress(now / total * 100.0); + } + }; + } + ok = client.download(url, dest, token, progress, last_modified, error); + if (ok) { + status.ok = true; + status.last_modified = std::move(last_modified); + return status; + } + status.error = error; + status.cancelled = error == "CANCELLED"; + } + if (status.cancelled) { + break; + } + ++attempt; + if (attempt < max_retries && on_retry) { + on_retry(attempt + 1, status.error); + } + } + return status; +} + +DownloadStatus download_json( + net::HttpClient &client, const std::string &url, net::CancelToken &token, + const std::function &on_retry, + int max_retries) { + DownloadStatus status; + int attempt = 0; + while (attempt < max_retries) { + if (attempt > 0) { + std::this_thread::sleep_for( + std::chrono::seconds(backoff_seconds(attempt))); + } + if (token.cancelled()) { + status.cancelled = true; + break; + } + const net::HttpResponse response = client.get(url); + const bool success = response.status >= 200 && response.status < 300; + if (success) { + status.ok = true; + status.body = response.body; + status.last_modified = response.last_modified; + return status; + } + status.error = "GET failed: " + std::to_string(response.status); + ++attempt; + if (attempt < max_retries && on_retry) { + on_retry(attempt + 1, status.error); + } + } + return status; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Downloader.hpp b/src/Instances/Downloader.hpp new file mode 100644 index 0000000..c176ccd --- /dev/null +++ b/src/Instances/Downloader.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "Core/Json.hpp" +#include "Net/HttpClient.hpp" +#include +#include +#include +#include +namespace emerald::instances { +struct DownloadStatus { + bool ok = false; + bool cancelled = false; + std::string error; + std::optional last_modified; + std::string body; +}; + +DownloadStatus download_file( + net::HttpClient &client, const std::string &url, + const std::filesystem::path &dest, net::CancelToken &token, + const std::function &on_progress = nullptr, + const std::function &on_retry = + nullptr, + int max_retries = 3); + +DownloadStatus download_json( + net::HttpClient &client, const std::string &url, net::CancelToken &token, + const std::function &on_retry = + nullptr, + int max_retries = 3); + +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Editions.cpp b/src/Instances/Editions.cpp new file mode 100644 index 0000000..d417edc --- /dev/null +++ b/src/Instances/Editions.cpp @@ -0,0 +1,114 @@ +#include "Instances/Editions.hpp" +namespace emerald::instances { +namespace { +const std::vector &build_base_editions() { + static const std::vector editions{ + {"legacy_evolved", "neoLegacy", + "Backporting newer title updates and Minigames back to LCE", + "https://git.neolegacy.dev/neoStudiosLCE/neoLegacy/releases/download/" + "latest/neoLegacyWindows64.zip", + "/images/minecraft_title_neoLegacy.png", "/images/neoLegacy.png", + "legacy_evolved", "", true, false, false, false, false, false}, + {"cafeberry", "Cafeberry", + "Project aiming to faithfully backport TUs, add cross-play and more!", + "https://gitea.str1k3r.xyz/cafeberry/cafeberry/releases/download/latest/" + "LCEWindows64.zip", + "/images/cafeberry_title.png", "", "vanilla_tu24", "", false, false, + false, false, false, false}, + {"revelations", "Legacy Revelations", + "QoL, performance, hardcore mode, & security features for LCE.", + "https://git.revela.dev/itsRevela/LCE-Revelations/releases/download/" + "Nightly/LCE-Revelations-Client-Win64.zip", + "/images/minecraft_title_revelations.png", "/images/revelations.png", + "vanilla_tu19", "", false, true, false, false, false, false}, + {"refourj", "ReFourJ", + "A LCE Project which aims to bring the feel and functionality from " + "Minecraft: Playstation Edition directly natively to your PC!", + "https://git.neolegacy.dev/ProjectLCE/Client/releases/download/latest/" + "MinecraftPS4Edition.zip", + "/images/MinecraftPS4Edition.png", "/images/projectlce.png", + "legacyorbis", "", true, false, false, false, false, false}, + {"lostlegacy", "Minecraft Lost Legacy", + "Downporting project aiming at bringing back the feel of Title Update 1 " + "with extra QoL features.", + "no", "/images/lostlegacy_title.png", "/images/lostlegacy.png", + "vanilla_tu1", "", false, false, true, false, false, false}, + {"360revived", "360 Revived", "PC port of Xbox 360 Edition TU19", + "emerald://PLEASE_IM_TIRED_OF_ALL_THIS", + "/images/minecraft_title_360revived.png", "/images/360_revived.png", + "360revived", "", false, false, false, true, false, true}, + {"legacy_nether_fork", "Hellish Ends", + "QoL, Random additions, and Nether/End/Aether dimensions overhaul " + "(Modded build!)", + "https://github.com/deadvoxelx/ThatModdedRepo/releases/download/nightly/" + "LCEWindows64.zip", + "/images/minecraft_title_hellishends.png", "/images/hellishEndsIcon.png", + "hellishends", "", false, false, false, false, false, false}, + {"moon_edition", "Minecraft: Moon Edition", + "Galacticraft LCE port (Modded build!)", + "https://github.com/blazin-blaze/moon-edition/releases/latest/download/" + "moonEditionWindows64.zip", + "/images/minecraft_title_moon.png", "/images/moonEdition.png", + "moonedition", "", false, true, false, false, false, false}, + {"lceonline", "LCE Online Client", + "[DISCONTINUED!] Restoring the classic LCE online experience with " + "friends, world hosting, leaderboards & more.", + "emerald://PLEASE_IM_TIRED_OF_ALL_THIS", "/images/lceonline.png", + "/images/lce_online.png", "vanilla_tu19", "", false, true, false, true, + true, false}, + }; + return editions; +} +} // namespace + +const std::vector &base_editions() { return build_base_editions(); } +std::vector resolve_editions( + const std::vector &custom_editions, + const std::vector> &overrides) { + const auto apply_override = + [](Edition &edition, + const std::vector> &source) { + for (const auto &[id, override_edition] : source) { + if (id != edition.id) { + continue; + } + if (!override_edition.title_image.empty()) { + edition.title_image = override_edition.title_image; + } + if (!override_edition.panorama.empty()) { + edition.panorama = override_edition.panorama; + } + break; + } + }; + + std::vector editions; + editions.reserve(base_editions().size() + custom_editions.size()); + for (Edition edition : base_editions()) { + apply_override(edition, overrides); + editions.push_back(std::move(edition)); + } + for (Edition edition : custom_editions) { + apply_override(edition, overrides); + editions.push_back(std::move(edition)); + } + return editions; +} + +std::string edition_download_url(const Edition &edition, + const std::string &branch) { + const std::string marker = "/releases/download/"; + const std::size_t position = edition.url.find(marker); + if (position == std::string::npos || branch.empty()) { + return edition.url; + } + + const std::size_t after = position + marker.size(); + const std::size_t last_slash = edition.url.rfind('/'); + if (last_slash == std::string::npos || last_slash < after) { + return edition.url; + } + const std::string filename = edition.url.substr(last_slash + 1); + return edition.url.substr(0, after) + branch + "/" + filename; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Editions.hpp b/src/Instances/Editions.hpp new file mode 100644 index 0000000..fa435de --- /dev/null +++ b/src/Instances/Editions.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include +namespace emerald::instances { +struct Edition { + std::string id; + std::string name; + std::string desc; + std::string url; + std::string title_image; + std::string logo; + std::string panorama; + std::string category; + bool supports_slim_skins = false; + bool transparent_logo = false; + bool coming_soon = false; + bool hidden = false; + bool lce_online = false; + bool hide_on_android = false; +}; + +const std::vector &base_editions(); +std::vector +resolve_editions(const std::vector &custom_editions, + const std::vector> &overrides); + +std::string edition_download_url(const Edition &edition, + const std::string &branch); + +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Installer.cpp b/src/Instances/Installer.cpp new file mode 100644 index 0000000..415afb3 --- /dev/null +++ b/src/Instances/Installer.cpp @@ -0,0 +1,243 @@ +#include "Instances/Installer.hpp" +#include "Core/Fs.hpp" +#include "Instances/InstanceManager.hpp" +#include "Instances/Workshop.hpp" +#include +#include +#include +#include +namespace emerald::instances { +namespace { +bool safe_path_within(const std::filesystem::path &base, + const std::filesystem::path &target) { + const std::filesystem::path root = std::filesystem::weakly_canonical(base); + std::error_code error; + const std::filesystem::path resolved = + std::filesystem::weakly_canonical(target, error); + const std::string root_str = root.string(); + const std::string target_str = error ? target.string() : resolved.string(); + if (target_str.size() < root_str.size()) { + return false; + } + if (target_str.compare(0, root_str.size(), root_str) != 0) { + return false; + } + return target_str.size() == root_str.size() || + target_str[root_str.size()] == '/'; +} + +void write_from_archive(struct archive *archive, struct archive_entry *entry, + const std::filesystem::path &dest) { + const mode_t mode = archive_entry_perm(entry); + const void *buffer = nullptr; + size_t size = 0; + la_ssize_t offset = 0; + std::FILE *out = std::fopen(dest.string().c_str(), "wb"); + if (out == nullptr) { + return; + } + while (archive_read_data_block(archive, &buffer, &size, &offset) == + ARCHIVE_OK) { + const size_t written = std::fwrite(buffer, 1, size, out); + if (written != size) { + break; + } + } + std::fclose(out); + if (mode != 0) { + chmod(dest.string().c_str(), static_cast(mode) & 0777); + } +} + +bool names_match_keep(const std::filesystem::path &child, + const std::vector &keep) { + const std::string name = child.filename().string(); + for (const std::string &entry : keep) { + if (entry == name) { + return true; + } + } + return false; +} + +bool is_workshop_path(const std::filesystem::path &child, + const std::vector &workshop_files) { + const std::string child_str = child.string(); + for (const std::string &workshop : workshop_files) { + if (workshop.empty()) { + continue; + } + if (child_str.compare(0, workshop.size(), workshop) == 0 || + workshop.compare(0, child_str.size(), child_str) == 0) { + return true; + } + } + return false; +} +} // namespace + +bool extract_archive(const std::filesystem::path &archive, + const std::filesystem::path &dest, std::string &error) { + return extract_archive_strip(archive, dest, 0, error); +} + +bool extract_archive_strip(const std::filesystem::path &archive, + const std::filesystem::path &dest, + int strip_components, std::string &error) { + if (!core::ensure_directory(dest)) { + error = "Failed to create destination directory"; + return false; + } + + struct archive *input = archive_read_new(); + archive_read_support_filter_all(input); + archive_read_support_format_all(input); + if (archive_read_open_filename(input, archive.string().c_str(), 10240) != + ARCHIVE_OK) { + error = archive_error_string(input); + archive_read_free(input); + return false; + } + + struct archive_entry *entry = nullptr; + bool ok = true; + while (archive_read_next_header(input, &entry) == ARCHIVE_OK) { + const std::string entry_path = archive_entry_pathname(entry); + if (entry_path.empty()) { + continue; + } + + std::string relative = entry_path; + for (int skipped = 0; skipped < strip_components; ++skipped) { + const std::size_t slash = relative.find('/'); + if (slash == std::string::npos) { + relative.clear(); + break; + } + relative.erase(0, slash + 1); + } + if (relative.empty()) { + continue; + } + + const std::filesystem::path target = dest / std::filesystem::path(relative); + if (!safe_path_within(dest, target)) { + error = "Archive entry escapes destination"; + ok = false; + break; + } + if (archive_entry_filetype(entry) == AE_IFDIR) { + core::ensure_directory(target); + continue; + } + if (archive_entry_filetype(entry) == AE_IFLNK) { + const char *link = archive_entry_symlink(entry); + if (link != nullptr) { + std::error_code link_error; + std::filesystem::remove(target, link_error); + std::filesystem::create_symlink(link, target, link_error); + } + continue; + } + core::ensure_directory(target.parent_path()); + write_from_archive(input, entry, target); + } + + const int read_result = archive_read_free(input); + if (!ok) { + return false; + } + if (read_result != ARCHIVE_OK) { + error = "Archive read failed"; + return false; + } + return true; +} + +void prune_instance(const std::filesystem::path &instance_dir, + const std::vector &keep, + const std::vector &workshop_files) { + std::error_code error; + std::filesystem::directory_iterator it(instance_dir, error); + if (error) { + return; + } + for (const std::filesystem::directory_entry &entry : it) { + const std::filesystem::path child = entry.path(); + if (names_match_keep(child, keep)) { + continue; + } + if (is_workshop_path(child, workshop_files)) { + continue; + } + remove_all(child, error); + error.clear(); + } +} + +void flatten_instance(const std::filesystem::path &instance_dir) { + std::error_code error; + std::filesystem::directory_iterator it(instance_dir, error); + if (error) { + return; + } + std::filesystem::path only_child; + std::size_t count = 0; + for (const std::filesystem::directory_entry &entry : it) { + ++count; + only_child = entry.path(); + } + if (count != 1 || !std::filesystem::is_directory(only_child, error)) { + return; + } + std::error_code move_error; + for (const std::filesystem::directory_entry &entry : + std::filesystem::directory_iterator(only_child, move_error)) { + const std::filesystem::path target = instance_dir / entry.path().filename(); + std::filesystem::rename(entry.path(), target, move_error); + move_error.clear(); + } + remove_all(only_child, move_error); +} + +DownloadStatus install_instance_archive( + net::HttpClient &client, const std::string &url, + const std::filesystem::path &instance_dir, + const std::filesystem::path &archive_dir, net::CancelToken &token, + const std::function &on_progress) { + DownloadStatus status; + if (!core::ensure_directory(archive_dir)) { + status.error = "Failed to create archive directory"; + return status; + } + if (!core::ensure_directory(instance_dir)) { + status.error = "Failed to create instance directory"; + return status; + } + + const std::filesystem::path archive = archive_dir / "instance.tar.gz"; + status = download_file(client, url, archive, token, on_progress); + if (!status.ok) { + return status; + } + if (token.cancelled()) { + status.cancelled = true; + return status; + } + prune_instance(instance_dir, keep_list(), read_workshop_files(instance_dir)); + std::string error; + const bool extracted = extract_archive(archive, instance_dir, error); + std::error_code cleanup_error; + std::filesystem::remove(archive, cleanup_error); + if (!extracted) { + status.error = error; + return status; + } + flatten_instance(instance_dir); + if (status.last_modified) { + core::write_file_atomic(instance_dir / "update_timestamp.txt", + *status.last_modified); + } + return status; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Installer.hpp b/src/Instances/Installer.hpp new file mode 100644 index 0000000..fe37da8 --- /dev/null +++ b/src/Instances/Installer.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "Instances/Downloader.hpp" +#include +#include +#include +namespace emerald::instances { +bool extract_archive(const std::filesystem::path &archive, + const std::filesystem::path &dest, std::string &error); + +bool extract_archive_strip(const std::filesystem::path &archive, + const std::filesystem::path &dest, + int strip_components, std::string &error); + +void prune_instance(const std::filesystem::path &instance_dir, + const std::vector &keep, + const std::vector &workshop_files); + +void flatten_instance(const std::filesystem::path &instance_dir); +DownloadStatus install_instance_archive( + net::HttpClient &client, const std::string &url, + const std::filesystem::path &instance_dir, + const std::filesystem::path &archive_dir, net::CancelToken &token, + const std::function &on_progress = nullptr); + +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/InstanceManager.cpp b/src/Instances/InstanceManager.cpp new file mode 100644 index 0000000..f62a7e9 --- /dev/null +++ b/src/Instances/InstanceManager.cpp @@ -0,0 +1,88 @@ +#include "Instances/InstanceManager.hpp" +#include "Core/Paths.hpp" +namespace emerald::instances { +namespace { +const std::vector kKeepList{ + "Windows64", + "Windows64Media", + "uid.dat", + "username.txt", + "settings.dat", + "servers.dat", + "servers.txt", + "server.properties", + "options.txt", + "servers.db", + "workshop_files.json", + "screenshots", + "update_timestamp.txt", + "profile0.dat", + "profile1.dat", + "profile2.dat", + "profile3.dat", + "profile4.dat", + "profile5.dat", + "profile6.dat", + "profile7.dat", + "profile8.dat", + "profile9.dat", + "profile10.dat", + "proton_prefix", +}; +} + +InstanceManager::InstanceManager(const config::AppConfig &config) + : config_(config) {} + +std::filesystem::path +InstanceManager::default_dir(std::string_view instance_id) const { + return core::instances_dir() / std::string(instance_id); +} + +std::filesystem::path +InstanceManager::working_dir(std::string_view instance_id) const { + if (config_.custom_editions.has_value()) { + for (const config::CustomEdition &edition : *config_.custom_editions) { + if (edition.id == instance_id && edition.path.has_value() && + !edition.path->empty()) { + return std::filesystem::path(*edition.path); + } + } + } + if (config_.custom_paths.has_value()) { + const auto found = config_.custom_paths->find(std::string(instance_id)); + if (found != config_.custom_paths->end() && !found->second.empty()) { + return std::filesystem::path(found->second); + } + } + return default_dir(instance_id); +} + +bool InstanceManager::is_installed(std::string_view instance_id) const { + return std::filesystem::exists(working_dir(instance_id) / + std::string(kExecutableMarker)); +} + +bool InstanceManager::is_managed(std::string_view instance_id) const { + return working_dir(instance_id) == default_dir(instance_id); +} + +bool InstanceManager::create_dir(std::string_view instance_id) const { + std::error_code error; + return std::filesystem::create_directories(working_dir(instance_id), error); +} + +bool InstanceManager::delete_instance(std::string_view instance_id) const { + if (!is_managed(instance_id)) { + return false; + } + const std::filesystem::path dir = default_dir(instance_id); + if (!std::filesystem::exists(dir)) { + return true; + } + std::error_code error; + return std::filesystem::remove_all(dir, error) > 0; +} + +const std::vector &keep_list() { return kKeepList; } +} // namespace emerald::instances diff --git a/src/Instances/InstanceManager.hpp b/src/Instances/InstanceManager.hpp new file mode 100644 index 0000000..e2e9c12 --- /dev/null +++ b/src/Instances/InstanceManager.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "Config/ConfigSchema.hpp" +#include +#include +#include +#include +namespace emerald::instances { +class InstanceManager { +public: + explicit InstanceManager(const config::AppConfig &config); + std::filesystem::path working_dir(std::string_view instance_id) const; + std::filesystem::path default_dir(std::string_view instance_id) const; + bool is_installed(std::string_view instance_id) const; + bool is_managed(std::string_view instance_id) const; + bool create_dir(std::string_view instance_id) const; + bool delete_instance(std::string_view instance_id) const; + +private: + const config::AppConfig &config_; +}; + +const std::vector &keep_list(); +constexpr std::string_view kExecutableMarker = "Minecraft.Client.exe"; +} // namespace emerald::instances diff --git a/src/Instances/InstanceSync.cpp b/src/Instances/InstanceSync.cpp new file mode 100644 index 0000000..fe5d404 --- /dev/null +++ b/src/Instances/InstanceSync.cpp @@ -0,0 +1,50 @@ +#include "Instances/InstanceSync.hpp" +#include "Core/Fs.hpp" +namespace emerald::instances { +bool sync_instance(const std::filesystem::path &instance_dir, + const std::string &username, + const std::filesystem::path &dlc_source, + const std::filesystem::path &skin_pck) { + std::error_code error; + if (!std::filesystem::is_directory(instance_dir, error)) { + return false; + } + + core::write_file(instance_dir / "username.txt", username); + if (!skin_pck.empty() && core::file_exists(skin_pck)) { + const std::filesystem::path skin_dir = + instance_dir / "Windows64Media" / "DLC" / "Custom Skins"; + if (core::ensure_directory(skin_dir)) { + core::copy_file(skin_pck, skin_dir / "Skin.pck"); + } + } + + if (dlc_source.empty() || !std::filesystem::is_directory(dlc_source, error)) { + return true; + } + + const std::filesystem::path dlc_dest = + instance_dir / "Windows64Media" / "DLC"; + if (!core::ensure_directory(dlc_dest)) { + return false; + } + + std::filesystem::directory_iterator it(dlc_source, error); + if (error) { + return false; + } + for (const std::filesystem::directory_entry &entry : it) { + const std::filesystem::path target = dlc_dest / entry.path().filename(); + std::error_code entry_error; + if (std::filesystem::exists(target, entry_error)) { + continue; + } + if (entry.is_directory(entry_error)) { + core::copy_directory(entry.path(), target); + } else { + core::copy_file(entry.path(), target); + } + } + return true; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/InstanceSync.hpp b/src/Instances/InstanceSync.hpp new file mode 100644 index 0000000..4083580 --- /dev/null +++ b/src/Instances/InstanceSync.hpp @@ -0,0 +1,10 @@ +#pragma once +#include +#include +namespace emerald::instances { +bool sync_instance(const std::filesystem::path &instance_dir, + const std::string &username, + const std::filesystem::path &dlc_source, + const std::filesystem::path &skin_pck); + +} \ No newline at end of file diff --git a/src/Instances/Runners.cpp b/src/Instances/Runners.cpp new file mode 100644 index 0000000..23c176d --- /dev/null +++ b/src/Instances/Runners.cpp @@ -0,0 +1,178 @@ +#include "Instances/Runners.hpp" +#include "Core/Fs.hpp" +#include "Core/Paths.hpp" +#include "Instances/Downloader.hpp" +#include "Instances/Installer.hpp" +#include +#include +#include +namespace emerald::instances { +namespace { +std::string environment(const char *name) { + const char *value = std::getenv(name); + return value != nullptr ? std::string(value) : std::string{}; +} + +bool is_executable_file(const std::filesystem::path &path) { + std::error_code error; + return std::filesystem::is_regular_file(path, error) && + access(path.string().c_str(), X_OK) == 0; +} + +std::string find_in_path(const std::string &program) { + const std::string path_env = environment("PATH"); + std::size_t start = 0; + while (start <= path_env.size()) { + const std::size_t colon = path_env.find(':', start); + const std::string directory = path_env.substr( + start, colon == std::string::npos ? std::string::npos : colon - start); + if (!directory.empty()) { + const std::filesystem::path candidate = + std::filesystem::path(directory) / program; + if (is_executable_file(candidate)) { + return candidate.string(); + } + } + if (colon == std::string::npos) { + break; + } + start = colon + 1; + } + return {}; +} + +std::string to_lower(std::string value) { + for (char &character : value) { + if (character >= 'A' && character <= 'Z') { + character = static_cast(character - 'A' + 'a'); + } + } + return value; +} +} // namespace + +bool is_proton_runner(const Runner &runner) { return runner.type == "proton"; } +std::string runner_program(const Runner &runner) { + if (is_proton_runner(runner)) { + return (std::filesystem::path(runner.path) / "proton").string(); + } + return runner.path; +} + +std::filesystem::path RunnerManager::runners_dir() { + return core::app_data_dir() / "runners"; +} + +std::vector RunnerManager::available() const { + std::vector runners; + std::unordered_set seen; + const auto add = [&](const std::string &id, const std::string &name, + const std::string &path, const std::string &type) { + if (path.empty() || !seen.insert(path).second) { + return; + } + runners.push_back(Runner{id, name, path, type}); + }; + +#if defined(__linux__) + const std::string wine_path = find_in_path("wine"); + if (!wine_path.empty()) { + add("wine", "System Wine", wine_path, "wine"); + } + + const std::filesystem::path flatpak_wine = + "/usr/share/emerald-legacy-launcher/wine/bin/wine"; + if (is_executable_file(flatpak_wine)) { + add("flatpaksucks", "Default for Flatpak", flatpak_wine.string(), "wine"); + } + + const std::string home = environment("HOME"); + const std::vector steam_paths{ + std::filesystem::path(home) / ".local/share/Steam/compatibilitytools.d", + std::filesystem::path(home) / ".local/share/Steam/steamapps/common", + "/usr/share/Steam/compatibilitytools.d"}; + + for (const std::filesystem::path &base_path : steam_paths) { + std::error_code error; + std::filesystem::directory_iterator it(base_path, error); + if (error) { + continue; + } + for (const std::filesystem::directory_entry &entry : it) { + std::error_code entry_error; + if (!entry.is_directory(entry_error)) { + continue; + } + const std::string name = entry.path().filename().string(); + if (to_lower(name).find("proton") == std::string::npos) { + continue; + } + add("proton_" + name, name, entry.path().string(), "proton"); + } + } +#endif + + const std::filesystem::path runners_path = runners_dir(); + core::ensure_directory(runners_path); + std::error_code dir_error; + std::filesystem::directory_iterator it(runners_path, dir_error); + if (!dir_error) { + for (const std::filesystem::directory_entry &entry : it) { + std::error_code entry_error; + if (!entry.is_directory(entry_error)) { + continue; + } + const std::string dir_name = entry.path().filename().string(); + const std::filesystem::path proton_bin = entry.path() / "proton"; + const std::filesystem::path wine_bin = entry.path() / "bin" / "wine"; + if (core::file_exists(proton_bin)) { + add("downloaded_" + dir_name, dir_name + " (downloaded)", + entry.path().string(), "proton"); + } else if (core::file_exists(wine_bin)) { + add("downloaded_" + dir_name, dir_name + " (downloaded)", + wine_bin.string(), "wine"); + } + } + } + + return runners; +} + +bool RunnerManager::download_runner( + net::HttpClient &client, const std::string &name, const std::string &url, + net::CancelToken &token, + const std::function &on_progress, + std::string &error) { + const std::filesystem::path runners_path = runners_dir(); + if (!core::ensure_directory(runners_path)) { + error = "Failed to create runners directory"; + return false; + } + + const std::filesystem::path runner_dir = runners_path / name; + std::error_code remove_error; + std::filesystem::remove_all(runner_dir, remove_error); + if (!core::ensure_directory(runner_dir)) { + error = "Failed to create runner directory"; + return false; + } + + const std::filesystem::path tarball = runners_path / (name + ".tar.gz"); + const DownloadStatus status = + download_file(client, url, tarball, token, on_progress, nullptr, 3); + if (!status.ok) { + error = status.cancelled ? "CANCELLED" : status.error; + std::filesystem::remove_all(runner_dir, remove_error); + return false; + } + + const bool extracted = extract_archive_strip(tarball, runner_dir, 1, error); + std::error_code cleanup_error; + std::filesystem::remove(tarball, cleanup_error); + if (!extracted) { + std::filesystem::remove_all(runner_dir, cleanup_error); + return false; + } + return true; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Runners.hpp b/src/Instances/Runners.hpp new file mode 100644 index 0000000..3c6d40e --- /dev/null +++ b/src/Instances/Runners.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "Net/HttpClient.hpp" +#include +#include +#include +#include +namespace emerald::instances { +struct Runner { + std::string id; + std::string name; + std::string path; + std::string type; +}; + +bool is_proton_runner(const Runner &runner); +std::string runner_program(const Runner &runner); +class RunnerManager { +public: + std::vector available() const; + static std::filesystem::path runners_dir(); + static bool + download_runner(net::HttpClient &client, const std::string &name, + const std::string &url, net::CancelToken &token, + const std::function &on_progress, + std::string &error); +}; +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Workshop.cpp b/src/Instances/Workshop.cpp new file mode 100644 index 0000000..b67c581 --- /dev/null +++ b/src/Instances/Workshop.cpp @@ -0,0 +1,526 @@ +#include "Instances/Workshop.hpp" +#include "Core/Fs.hpp" +#include "Core/Json.hpp" +#include "Core/Paths.hpp" +#include "Instances/Installer.hpp" +#include +#include +#include +#include +#include +namespace emerald::instances { +namespace { +const char *kWorkshopRawBase = + "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main"; +std::string to_lower(std::string value) { + for (char &character : value) { + if (character >= 'A' && character <= 'Z') { + character = static_cast(character - 'A' + 'a'); + } + } + return value; +} + +std::vector read_string_list(const std::filesystem::path &path) { + std::vector values; + const std::optional text = core::read_file(path); + if (!text.has_value()) { + return values; + } + Json json = Json::array(); + try { + json = Json::parse(*text); + } catch (const std::exception &) { + return values; + } + if (!json.is_array()) { + return values; + } + for (const Json &item : json) { + if (item.is_string()) { + values.push_back(item.get()); + } + } + return values; +} + +std::vector +read_packages(const std::filesystem::path &path) { + std::vector packages; + const std::optional text = core::read_file(path); + if (!text.has_value()) { + return packages; + } + Json json = Json::array(); + try { + json = Json::parse(*text); + } catch (const std::exception &) { + return packages; + } + if (!json.is_array()) { + return packages; + } + for (const Json &item : json) { + if (!item.is_object()) { + continue; + } + InstalledWorkshopPackage package; + package.id = json_optional(item, "id").value_or(""); + package.version = json_optional(item, "version").value_or(""); + const auto dirs = json_optional(item, "dirs"); + if (dirs.has_value() && dirs->is_array()) { + for (const Json &dir : *dirs) { + if (dir.is_string()) { + package.dirs.push_back(dir.get()); + } + } + } + packages.push_back(std::move(package)); + } + return packages; +} + +std::string write_string_list(const std::filesystem::path &path, + const std::vector &values) { + Json json = Json::array(); + for (const std::string &value : values) { + json.push_back(value); + } + return core::write_file(path, json.dump()) + ? std::string() + : "Failed to write " + path.string(); +} + +std::string +write_packages(const std::filesystem::path &path, + const std::vector &packages) { + Json json = Json::array(); + for (const InstalledWorkshopPackage &package : packages) { + Json entry = Json::object(); + entry["id"] = package.id; + entry["version"] = package.version; + entry["dirs"] = package.dirs; + json.push_back(std::move(entry)); + } + return core::write_file(path, json.dump()) + ? std::string() + : "Failed to write " + path.string(); +} + +void replace_all(std::string &text, const std::string &from, + const std::string &to) { + if (from.empty()) { + return; + } + std::size_t position = 0; + while ((position = text.find(from, position)) != std::string::npos) { + text.replace(position, from.size(), to); + position += to.size(); + } +} + +std::string resolve_dest(const std::filesystem::path &instance_dir, + const std::string &placeholder) { + if (placeholder.empty()) { + return instance_dir.string(); + } + const std::filesystem::path media_dir = instance_dir / "Windows64Media"; + std::string resolved = placeholder; + replace_all(resolved, "{MediaDir}", media_dir.string()); + replace_all(resolved, "{DLCDir}", (media_dir / "DLC").string()); + replace_all(resolved, "{GameHDD}", + (instance_dir / "Windows64" / "GameHDD").string()); + replace_all(resolved, "{MobDir}", + (instance_dir / "Common" / "res" / "mob").string()); + return (instance_dir / std::filesystem::path(resolved)).string(); +} + +} // namespace + +std::vector +group_archives(const std::map &zips) { + std::vector groups; + std::unordered_set consumed; + for (const auto &[name, dest] : zips) { + if (consumed.count(name) != 0) { + continue; + } + if (to_lower(name).size() < 4 || + to_lower(name).compare(to_lower(name).size() - 4, 4, ".zip") != 0) { + continue; + } + + const std::string base = name.substr(0, name.size() - 4); + std::vector parts{name}; + consumed.insert(name); + int index = 1; + while (true) { + char suffix[8]; + std::snprintf(suffix, sizeof(suffix), ".z%02d", index); + const std::string candidate = base + suffix; + if (zips.find(candidate) == zips.end()) { + break; + } + parts.push_back(candidate); + consumed.insert(candidate); + ++index; + } + + if (parts.size() == 1) { + index = 1; + while (true) { + char suffix[16]; + std::snprintf(suffix, sizeof(suffix), ".zip.%03d", index); + const std::string candidate = base + suffix; + if (zips.find(candidate) == zips.end()) { + break; + } + parts.push_back(candidate); + consumed.insert(candidate); + ++index; + } + } + + groups.push_back(WorkshopGroup{parts, dest}); + } + + for (const auto &[name, dest] : zips) { + if (consumed.count(name) == 0) { + consumed.insert(name); + groups.push_back(WorkshopGroup{{name}, dest}); + } + } + + return groups; +} + +bool list_archive(const std::filesystem::path &archive, + std::vector &out, std::string &error) { + struct archive *input = archive_read_new(); + archive_read_support_filter_all(input); + archive_read_support_format_all(input); + if (archive_read_open_filename(input, archive.string().c_str(), 10240) != + ARCHIVE_OK) { + error = "Failed to open " + archive.string(); + archive_read_free(input); + return false; + } + + struct archive_entry *entry = nullptr; + while (archive_read_next_header(input, &entry) == ARCHIVE_OK) { + const char *name = archive_entry_pathname(entry); + if (name == nullptr) { + continue; + } + const std::string entry_name(name); + if (entry_name.empty() || entry_name.back() == '/' || + archive_entry_filetype(entry) == AE_IFDIR) { + continue; + } + out.push_back(entry_name); + } + archive_read_free(input); + return true; +} + +std::vector +read_workshop_files(const std::filesystem::path &instance_dir) { + return read_string_list(instance_dir / "workshop_files.json"); +} + +std::vector +read_workshop_packages(const std::filesystem::path &instance_dir) { + return read_packages(instance_dir / "workshop_packages.json"); +} + +bool WorkshopService::download_and_assemble( + const std::filesystem::path &tmp_dir, const std::vector &parts, + const std::string &raw_base, std::size_t &done, std::size_t total, + net::CancelToken &token, + const std::function &on_progress, + std::filesystem::path &out, std::string &error) { + std::vector downloaded; + for (const std::string &part : parts) { + if (token.cancelled()) { + error = "CANCELLED"; + return false; + } + + const std::filesystem::path part_path = tmp_dir / part; + if (!core::ensure_directory(part_path.parent_path())) { + error = "Failed to create temporary directory"; + return false; + } + + std::optional last_modified; + std::string download_error; + if (!client_.download(raw_base + "/" + part, part_path, token, nullptr, + last_modified, download_error)) { + error = "Failed to download " + part + ": " + download_error; + return false; + } + + ++done; + if (on_progress) { + const double divisor = total > 0 ? static_cast(total) : 1.0; + on_progress(static_cast(done) / divisor * 100.0); + } + downloaded.push_back(part_path); + } + + if (downloaded.size() == 1) { + out = downloaded.front(); + return true; + } + + const std::filesystem::path combined_dir = tmp_dir / "_combined"; + if (!core::ensure_directory(combined_dir)) { + error = "Failed to create temporary directory"; + return false; + } + + out = combined_dir / parts.front(); + std::FILE *target = std::fopen(out.string().c_str(), "wb"); + if (target == nullptr) { + error = "Failed to create combined archive"; + return false; + } + for (const std::filesystem::path &part_path : downloaded) { + std::FILE *source = std::fopen(part_path.string().c_str(), "rb"); + if (source == nullptr) { + std::fclose(target); + error = "Failed to read " + part_path.string(); + return false; + } + std::vector buffer(64 * 1024); + while (true) { + const std::size_t read = + std::fread(buffer.data(), 1, buffer.size(), source); + if (read == 0) { + break; + } + if (std::fwrite(buffer.data(), 1, read, target) != read) { + std::fclose(source); + std::fclose(target); + error = "Failed to write combined archive"; + return false; + } + } + std::fclose(source); + } + std::fclose(target); + return true; +} + +bool WorkshopService::install( + const WorkshopInstallRequest &request, net::CancelToken &token, + const std::function &on_progress, + std::string &error) { + const std::filesystem::path instance_dir = + instances_.working_dir(request.instance_id); + if (!std::filesystem::exists(instance_dir)) { + error = "Instance not installed"; + return false; + } + + const std::filesystem::path files_path = instance_dir / "workshop_files.json"; + const std::filesystem::path packages_path = + instance_dir / "workshop_packages.json"; + std::vector workshop_files = read_string_list(files_path); + std::vector workshop_packages = + read_packages(packages_path); + workshop_packages.erase( + std::remove_if(workshop_packages.begin(), workshop_packages.end(), + [&](const InstalledWorkshopPackage &package) { + return package.id == request.package_id; + }), + workshop_packages.end()); + + const std::string raw_base = + std::string(kWorkshopRawBase) + "/" + request.package_id; + const std::filesystem::path tmp_dir = + core::app_data_dir() / ("workshop_tmp_" + request.package_id); + std::error_code cleanup_error; + std::filesystem::remove_all(tmp_dir, cleanup_error); + if (!core::ensure_directory(tmp_dir)) { + error = "Failed to create temporary directory"; + return false; + } + + std::vector package_dirs; + const std::vector groups = group_archives(request.zips); + std::size_t done_parts = 0; + const std::size_t total_parts = request.zips.size(); + for (const WorkshopGroup &group : groups) { + const std::filesystem::path dest_dir( + resolve_dest(instance_dir, group.dest)); + if (!core::ensure_directory(dest_dir)) { + std::filesystem::remove_all(tmp_dir, cleanup_error); + error = "Failed to create destination directory"; + return false; + } + + std::filesystem::path archive_tmp; + if (!download_and_assemble(tmp_dir, group.parts, raw_base, done_parts, + total_parts, token, on_progress, archive_tmp, + error)) { + std::filesystem::remove_all(tmp_dir, cleanup_error); + return false; + } + + std::vector files; + if (!list_archive(archive_tmp, files, error)) { + std::filesystem::remove_all(tmp_dir, cleanup_error); + return false; + } + + for (const std::string &file : files) { + const std::filesystem::path full = dest_dir / file; + std::error_code file_error; + if (!std::filesystem::is_regular_file(full, file_error)) { + continue; + } + const std::filesystem::path backup = + std::filesystem::path(full.string() + ".bak"); + std::error_code backup_error; + if (!std::filesystem::exists(backup, backup_error)) { + std::error_code rename_error; + std::filesystem::rename(full, backup, rename_error); + } + } + + std::string extract_error; + if (!extract_archive(archive_tmp, dest_dir, extract_error)) { + std::filesystem::remove_all(tmp_dir, cleanup_error); + error = "Extraction failed for " + group.parts.front(); + return false; + } + + for (const std::string &file : files) { + const std::string full = (dest_dir / file).string(); + if (std::find(workshop_files.begin(), workshop_files.end(), full) == + workshop_files.end()) { + workshop_files.push_back(full); + } + if (std::find(package_dirs.begin(), package_dirs.end(), full) == + package_dirs.end()) { + package_dirs.push_back(full); + } + } + } + + std::filesystem::remove_all(tmp_dir, cleanup_error); + const std::string files_error = write_string_list(files_path, workshop_files); + if (!files_error.empty()) { + error = files_error; + return false; + } + + workshop_packages.push_back(InstalledWorkshopPackage{ + request.package_id, request.version, package_dirs}); + const std::string packages_error = + write_packages(packages_path, workshop_packages); + if (!packages_error.empty()) { + error = packages_error; + return false; + } + return true; +} + +bool WorkshopService::uninstall(const std::string &instance_id, + const std::string &package_id, + std::string &error) { + const std::filesystem::path instance_dir = + instances_.working_dir(instance_id); + const std::filesystem::path packages_path = + instance_dir / "workshop_packages.json"; + const std::filesystem::path files_path = instance_dir / "workshop_files.json"; + std::vector packages = read_packages(packages_path); + std::vector removed_dirs; + for (const InstalledWorkshopPackage &package : packages) { + if (package.id != package_id) { + continue; + } + removed_dirs = package.dirs; + for (const std::string &file : package.dirs) { + const std::filesystem::path path(file); + std::error_code file_error; + if (!std::filesystem::is_regular_file(path, file_error)) { + continue; + } + std::filesystem::remove(path, file_error); + const std::filesystem::path backup(std::filesystem::path(file + ".bak")); + std::error_code backup_error; + if (std::filesystem::is_regular_file(backup, backup_error)) { + std::error_code rename_error; + std::filesystem::rename(backup, path, rename_error); + } + } + break; + } + + packages.erase(std::remove_if(packages.begin(), packages.end(), + [&](const InstalledWorkshopPackage &package) { + return package.id == package_id; + }), + packages.end()); + const std::string packages_error = write_packages(packages_path, packages); + if (!packages_error.empty()) { + error = packages_error; + return false; + } + + std::vector workshop_files = read_string_list(files_path); + workshop_files.erase( + std::remove_if(workshop_files.begin(), workshop_files.end(), + [&](const std::string &file) { + return std::find(removed_dirs.begin(), + removed_dirs.end(), + file) != removed_dirs.end(); + }), + workshop_files.end()); + const std::string files_error = write_string_list(files_path, workshop_files); + if (!files_error.empty()) { + error = files_error; + return false; + } + return true; +} + +std::vector WorkshopService::list_installed() const { + std::vector result; + const std::filesystem::path managed_root = core::instances_dir(); + std::error_code root_error; + std::filesystem::directory_iterator root_it(managed_root, root_error); + if (!root_error) { + for (const std::filesystem::directory_entry &entry : root_it) { + std::error_code entry_error; + if (!entry.is_directory(entry_error)) { + continue; + } + const std::string instance_id = entry.path().filename().string(); + for (const InstalledWorkshopPackage &package : + read_packages(entry.path() / "workshop_packages.json")) { + result.push_back( + InstalledPackageEntry{instance_id, package.id, package.version}); + } + } + } + + if (config_.custom_editions.has_value()) { + for (const config::CustomEdition &edition : *config_.custom_editions) { + if (!edition.path.has_value() || edition.path->empty()) { + continue; + } + const std::filesystem::path base_dir(*edition.path); + for (const InstalledWorkshopPackage &package : + read_packages(base_dir / "workshop_packages.json")) { + result.push_back( + InstalledPackageEntry{edition.id, package.id, package.version}); + } + } + } + + return result; +} +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Instances/Workshop.hpp b/src/Instances/Workshop.hpp new file mode 100644 index 0000000..54b02ad --- /dev/null +++ b/src/Instances/Workshop.hpp @@ -0,0 +1,72 @@ +#pragma once +#include "Instances/InstanceManager.hpp" +#include "Net/HttpClient.hpp" +#include +#include +#include +#include +#include +#include +namespace emerald::instances { +struct InstalledWorkshopPackage { + std::string id; + std::string version; + std::vector dirs; +}; + +struct InstalledPackageEntry { + std::string instance_id; + std::string package_id; + std::string version; +}; + +struct WorkshopInstallRequest { + std::string instance_id; + std::map zips; + std::string package_id; + std::string version; +}; + +struct WorkshopGroup { + std::vector parts; + std::string dest; +}; + +std::vector +group_archives(const std::map &zips); +bool list_archive(const std::filesystem::path &archive, + std::vector &out, std::string &error); + +std::vector +read_workshop_files(const std::filesystem::path &instance_dir); +std::vector +read_workshop_packages(const std::filesystem::path &instance_dir); +class WorkshopService { +public: + WorkshopService(const InstanceManager &instances, + const config::AppConfig &config, net::HttpClient &client) + : instances_(instances), config_(config), client_(client) {} + + bool install(const WorkshopInstallRequest &request, net::CancelToken &token, + const std::function &on_progress, + std::string &error); + + bool uninstall(const std::string &instance_id, const std::string &package_id, + std::string &error); + + std::vector list_installed() const; + +private: + bool + download_and_assemble(const std::filesystem::path &tmp_dir, + const std::vector &parts, + const std::string &raw_base, std::size_t &done, + std::size_t total, net::CancelToken &token, + const std::function &on_progress, + std::filesystem::path &out, std::string &error); + + const InstanceManager &instances_; + const config::AppConfig &config_; + net::HttpClient &client_; +}; +} // namespace emerald::instances \ No newline at end of file diff --git a/src/Integrations/DiscordRpc.cpp b/src/Integrations/DiscordRpc.cpp new file mode 100644 index 0000000..ca56667 --- /dev/null +++ b/src/Integrations/DiscordRpc.cpp @@ -0,0 +1,187 @@ +#include "Integrations/DiscordRpc.hpp" +#include "Core/Log.hpp" +#include "discord_ipc_cpp/discord_ipc_client.hpp" +#include "discord_ipc_cpp/ipc_types.hpp" +#include +#include +#include +#include +namespace emerald::integrations { +using discord_ipc_cpp::DiscordIPCClient; +using ActivityType = discord_ipc_cpp::ipc_types::RichPresence::ActivityType; +using Assets = discord_ipc_cpp::ipc_types::RichPresence::Assets; +using Button = discord_ipc_cpp::ipc_types::RichPresence::Button; +using Party = discord_ipc_cpp::ipc_types::RichPresence::Party; +using discord_ipc_cpp::ipc_types::RichPresence; +using StatusDisplayType = + discord_ipc_cpp::ipc_types::RichPresence::StatusDisplayType; +using Timestamps = discord_ipc_cpp::ipc_types::RichPresence::Timestamps; +namespace { +constexpr const char *kClientId = "1482504445152460871"; +constexpr const char *kPublicAssetBase = "https://raw.githubusercontent.com/LCE-Hub/LCE-Emerald-Launcher/refs/heads/main/public"; +constexpr const char *kDefaultLogo = "logo"; +constexpr int kRefreshMillis = 750; +std::string asset_url(const std::string &logo) { + if (logo.empty()) { + return kDefaultLogo; + } + if (logo.rfind("https://", 0) == 0 || logo.rfind("http://", 0) == 0) { + return logo; + } + if (logo.rfind("/images/", 0) == 0) { + return std::string(kPublicAssetBase) + logo; + } + return kDefaultLogo; +} + +std::string view_details(const std::string &view) { + if (view == "home" || view == "main" || view.empty()) { + return "Main Menu"; + } + if (view == "versions") { + return "Selecting Version"; + } + if (view == "settings") { + return "In Settings"; + } + return "In Menus"; +} +} // namespace + +DiscordRpc::DiscordRpc() { + start_time_ = static_cast( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count()); +} + +DiscordRpc::~DiscordRpc() { shutdown(); } +void DiscordRpc::configure(const config::ConfigStore &config) { + enabled_.store(config.data().rpc_enabled.value_or(true)); +} + +void DiscordRpc::update(const DiscordState &state) { + { + std::lock_guard lock(state_mutex_); + pending_state_ = state; + } + if (running_.exchange(true)) { + return; + } + stop_.store(false); + worker_ = std::thread([this] { run(); }); +} + +void DiscordRpc::run() { + while (!stop_.load()) { + DiscordState state; + { + std::lock_guard lock(state_mutex_); + state = pending_state_; + } + if (state.enabled && enabled_.load()) { + if (ensure_started()) { + refresh(state); + } + } else { + stop_client(); + } + for (int tick = 0; tick < kRefreshMillis / 50 && !stop_.load(); ++tick) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + stop_client(); + running_.store(false); +} + +void DiscordRpc::shutdown() { + stop_.store(true); + if (worker_.joinable()) { + worker_.join(); + } +} + +bool DiscordRpc::ensure_started() { + if (started_ && client_) { + return true; + } + client_ = std::make_unique(kClientId); + if (!client_->connect()) { + core::warn("discordrpc: failed to connect to discord ipc"); + client_.reset(); + started_ = false; + return false; + } + started_ = true; + return true; +} + +void DiscordRpc::stop_client() { + client_.reset(); + started_ = false; +} + +void DiscordRpc::refresh(const DiscordState &state) { + RichPresence presence; + presence.name = "Emerald Launcher"; + presence.type = ActivityType::at_game; + presence.status_display_type = StatusDisplayType::sdt_details; + std::string details; + std::string status; + std::string large_image = kDefaultLogo; + std::string large_text = "LCE Emerald Launcher"; + if (state.running) { + const std::string version = state.version_name.empty() ? "Game" : state.version_name; + details = version; + if (state.multiplayer) { + details += " Multiplayer"; + } + status = + state.username.empty() ? "In Game" : "Playing as " + state.username; + large_image = asset_url(state.instance_logo); + large_text = version; + } else if (state.downloading_count > 0 && !state.downloading_id.empty()) { + const std::string name = + state.downloading_name.empty() ? "Game Files" : state.downloading_name; + const std::string extra = + state.downloading_count > 1 + ? " +" + std::to_string(state.downloading_count - 1) + " more" + : ""; + details = "Downloading " + name + extra + " (" + + std::to_string(state.download_percent) + "%)"; + status = state.username.empty() ? "Emerald Launcher" + : "Logged in as " + state.username; + } else { + details = view_details(state.view); + status = state.username.empty() ? "Emerald Launcher" + : "Logged in as " + state.username; + } + + presence.details = details; + presence.state = status; + if (state.running && !state.username.empty()) { + Party party; + party.id = "emerald_" + state.username; + party.size = {1, 2}; + presence.party = party; + } + + Assets assets; + assets.large_image = large_image; + assets.large_text = large_text; + assets.small_image = kDefaultLogo; + assets.small_text = + state.running + ? (state.version_name.empty() ? "Playing" : state.version_name) + : "Emerald Launcher"; + presence.assets = assets; + Timestamps timestamps; + timestamps.start = static_cast(start_time_); + presence.timestamps = timestamps; + presence.buttons = std::vector - - -
- )} - - ); -}); - -export default SkinViewer; diff --git a/src/components/layout/AppHeader.tsx b/src/components/layout/AppHeader.tsx deleted file mode 100644 index 0b45c67..0000000 --- a/src/components/layout/AppHeader.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { getCurrentWindow } from "@tauri-apps/api/window"; -import { motion } from "framer-motion"; -import { memo } from "react"; -import { useTranslation } from "react-i18next"; - -const appWindow = getCurrentWindow(); - -interface AppHeaderProps { - playPressSound: () => void; - uiFade: Record; -} - -export const AppHeader = memo(function AppHeader({ - playPressSound, - uiFade, -}: AppHeaderProps) { - const { t } = useTranslation(); - return ( - -
- Icon - - {t("header.title")} - -
-
- - - -
-
- ); -}); diff --git a/src/components/layout/DownloadOverlay.tsx b/src/components/layout/DownloadOverlay.tsx deleted file mode 100644 index 0d9d630..0000000 --- a/src/components/layout/DownloadOverlay.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { motion } from "framer-motion"; -import { memo } from "react"; -import { useTranslation } from "react-i18next"; -import { ScreenshotImage } from "../common/ScreenshotImage"; -import type { Edition } from "../../types/edition"; - -interface DownloadOverlayProps { - downloadProgress: Record; - downloadingIds: string[]; - editions: Edition[]; -} - -export const DownloadOverlay = memo(function DownloadOverlay({ - downloadProgress, - downloadingIds, - editions, -}: DownloadOverlayProps) { - const { t } = useTranslation(); - if (downloadingIds.length === 0) return null; - - return ( - -
- {t("download.title")} -
-
- {downloadingIds.map((id) => { - const pct = downloadProgress[id] ?? 0; - const edition = editions.find( - (e) => e.instanceId === id || e.id === id, - ); - const name = - edition?.name || - (id.startsWith("runner_") - ? id.replace(/^runner_/, "") - : t("download.gameFiles")); - return ( -
-
-
-
- {edition?.logo ? ( - edition.logo.startsWith("http") || - edition.logo.startsWith("/images") ? ( - - ) : ( - - ) - ) : edition?.titleImage ? ( - edition.titleImage.startsWith("http") || - edition.titleImage.startsWith("/images") ? ( - - ) : ( - - ) - ) : ( -
- - - - - -
- )} - - {name} - -
- - {Math.floor(pct)}% - -
-
-
-
-
-
-
-
- ); - })} -
- - ); -}); diff --git a/src/components/modals/ChooseInstanceModal.tsx b/src/components/modals/ChooseInstanceModal.tsx deleted file mode 100644 index 105130b..0000000 --- a/src/components/modals/ChooseInstanceModal.tsx +++ /dev/null @@ -1,300 +0,0 @@ -import { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; -import { lceOnlineService } from "../../services/LceOnlineService"; -import type { Edition } from "../../types/edition"; -interface GameInvite { - inviteId: string; - from: string; - hostIp: string; - hostPort: number; - hostName: string; - sessionId?: string; - status: string; -} - -export default function ChooseInstanceModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - editions, - installs, - invite, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - editions: Edition[]; - installs: string[]; - invite: GameInvite | null; -}) { - const { t } = useTranslation(); - const [selectedInstance, setSelectedInstance] = useState(""); - const [status, setStatus] = useState(""); - const [error, setError] = useState(""); - const [isJoining, setIsJoining] = useState(false); - const [focusIndex, setFocusIndex] = useState(0); - const validInstances = editions.filter((e: Edition) => - installs.includes(e.instanceId), - ); - - useEffect(() => { - if (!isOpen) { - setSelectedInstance(""); - setStatus(""); - setError(""); - setIsJoining(false); - setFocusIndex(0); - } - }, [isOpen]); - - useEffect(() => { - if (isOpen && validInstances.length > 0 && !selectedInstance) { - setSelectedInstance(validInstances[0].instanceId); - } - }, [isOpen, validInstances, selectedInstance]); - - const handleJoin = async () => { - if (!invite || !selectedInstance) return; - playPressSound(); - setIsJoining(true); - setError(""); - setStatus(t("modals.chooseInstance.launching")); - try { - const sessionId = invite.sessionId || ""; - if (sessionId) { - setStatus(t("modals.chooseInstance.connectingRelay")); - const accessToken = lceOnlineService.accessToken ?? ""; - const relayPromise = TauriService.startRelayProxy( - accessToken, - sessionId, - ); - setStatus(t("modals.chooseInstance.launching")); - await TauriService.launchGame( - selectedInstance, - [ - { - name: invite.hostName || "LCEOnline Game", - ip: "127.0.0.1", - port: 61000, - }, - ], - ["-ip", "127.0.0.1", "-port", "61000", "-quitondisconnect"], - ); - await relayPromise; - } else { - await TauriService.stopAllProxies(); - await TauriService.launchGame(selectedInstance, [ - { - name: invite.hostName || "LCEOnline Game", - ip: invite.hostIp, - port: invite.hostPort, - }, - ]); - } - onClose(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsJoining(false); - } - }; - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound(); - if (isJoining) return; - onClose(); - } else if (e.key === "ArrowDown" || e.key === "Tab") { - e.preventDefault(); - const max = 1 + (validInstances.length > 0 ? 1 : 0) + 1; - setFocusIndex((prev) => (prev + 1) % max); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - const max = 1 + (validInstances.length > 0 ? 1 : 0) + 1; - setFocusIndex((prev) => (prev - 1 + max) % max); - } else if (e.key === "Enter") { - e.preventDefault(); - if (focusIndex === 0 && validInstances.length > 0) { - const currentIdx = validInstances.findIndex( - (i: Edition) => i.instanceId === selectedInstance, - ); - const next = (currentIdx + 1) % validInstances.length; - setSelectedInstance(validInstances[next].instanceId); - playPressSound(); - } else if (focusIndex === 1 && !isJoining) { - handleJoin(); - } else if ( - focusIndex === (validInstances.length > 0 ? 2 : 1) && - !isJoining - ) { - onClose(); - } - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, focusIndex, selectedInstance, validInstances, isJoining]); - - if (!isOpen) return null; - const hostName = invite - ? typeof invite.from === "string" - ? invite.from - : invite.hostName - : ""; - - return ( - -
- {!isJoining ? ( - <> -

- {t("modals.chooseInstance.title")} -

-

- {t("modals.chooseInstance.joinPrompt", { - name: hostName, - })} -

- - {validInstances.length > 0 ? ( -
- {validInstances.map((inst: Edition) => { - const isSelected = selectedInstance === inst.instanceId; - return ( -
{ - playPressSound(); - setSelectedInstance(inst.instanceId); - }} - onMouseEnter={() => setFocusIndex(0)} - className={`w-full px-4 py-3 cursor-pointer flex items-center gap-3 transition-all outline-none border-none ${isSelected ? "bg-white/15 border-l-4 border-[#FFFF55]" : "bg-black/20 hover:bg-black/30 border-l-4 border-transparent"}`} - style={{ imageRendering: "pixelated" }} - > -
- {isSelected && ( -
- )} -
-
- - {inst.name} - - {inst.selectedBranch && ( - - {inst.selectedBranch} - - )} -
-
- ); - })} -
- ) : ( -

- {t("modals.chooseInstance.noInstances")} -

- )} - - {error && ( -
- {error} -
- )} - -
- - {validInstances.length > 0 && ( - - )} -
- - ) : ( - <> -

- {t("modals.chooseInstance.joiningTitle")} -

-
-
-

- {status} -

-
- {error && ( -
- {error} -
- )} - - )} -
- - ); -} diff --git a/src/components/modals/CustomTUModal.tsx b/src/components/modals/CustomTUModal.tsx deleted file mode 100644 index f5a5c4e..0000000 --- a/src/components/modals/CustomTUModal.tsx +++ /dev/null @@ -1,238 +0,0 @@ -import { useState, useEffect, memo } from "react"; -import { useTranslation } from "react-i18next"; - -interface ModalButtonProps { - label: string; - onClick: () => void; - isDanger?: boolean; -} - -const ModalButton = memo(function ModalButton({ - label, - onClick, - isDanger = false, -}: ModalButtonProps) { - const [isHovered, setIsHovered] = useState(false); - - return ( - - ); -}); - -export default function CustomTUModal({ - isOpen, - onClose, - onImport, - playPressSound, - playBackSound, - editingEdition = null, - initialPath = "", -}: { - isOpen: boolean; - onClose: () => void; - onImport: (ed: { name: string; desc: string; url: string; path?: string }) => void; - playPressSound: (sound?: string) => void; - playBackSound: (sound?: string) => void; - editingEdition?: { name: string; desc: string; url: string; path?: string } | null; - initialPath?: string; -}) { - const { t } = useTranslation(); - const [name, setName] = useState(""); - const [desc, setDesc] = useState(""); - const [url, setUrl] = useState(""); - const [path, setPath] = useState(""); - const [error, setError] = useState(""); - const [focusIndex, setFocusIndex] = useState(0); - - useEffect(() => { - if (isOpen && editingEdition) { - setName(editingEdition.name); - setDesc(editingEdition.desc); - setUrl(editingEdition.url); - setPath(editingEdition.path || ""); - } else if (isOpen && initialPath) { - setPath(initialPath); - } else if (!isOpen) { - setName(""); - setDesc(""); - setUrl(""); - setPath(""); - setError(""); - } - }, [editingEdition, isOpen, initialPath]); - - useEffect(() => { - if (!isOpen) { - setFocusIndex(0); - return; - } - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound("close_click.wav"); - onClose(); - } else if (e.key === "Enter") { - e.preventDefault(); - if (focusIndex === 3) { - playBackSound("close_click.wav"); - onClose(); - } else if (focusIndex === 4 || e.ctrlKey) { - playPressSound("save_click.wav"); - handleImport(); - } - } else if (e.key === "ArrowDown" || e.key === "Tab") { - e.preventDefault(); - setFocusIndex((prev) => (prev + 1) % 5); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setFocusIndex((prev) => (prev - 1 + 5) % 5); - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, focusIndex, name, desc, url, path]); - - if (!isOpen) return null; - - const handleImport = () => { - if (!name) { - setError(t("modals.customTu.nameRequired")); - return; - } - if (!url && !path) { - setError(t("modals.customTu.urlOrPathRequired")); - return; - } - if (url && !url.startsWith("http")) { - setError(t("modals.customTu.invalidUrl")); - return; - } - setError(""); - onImport({ name, desc: desc || t("modals.customTu.defaultDesc"), url, path: path || undefined }); - onClose(); - setName(""); - setDesc(""); - setUrl(""); - setPath(""); - }; - - return ( -
-
-

- {editingEdition ? t("modals.customTu.editTitle") : t("modals.customTu.importTitle")} -

- -
-
- -
- setName(e.target.value)} - onFocus={() => setFocusIndex(0)} - placeholder={t("modals.customTu.namePlaceholder")} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - style={{ imageRendering: "pixelated" }} - /> -
-
- -
- -
- setDesc(e.target.value)} - onFocus={() => setFocusIndex(1)} - placeholder={t("modals.customTu.descPlaceholder")} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - style={{ imageRendering: "pixelated" }} - /> -
-
- -
- -
- setUrl(e.target.value)} - onFocus={() => setFocusIndex(2)} - placeholder={t("modals.customTu.urlPlaceholder")} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - style={{ imageRendering: "pixelated" }} - /> -
-
- - {path && ( -
- -
- -
-
- )} - - {error && ( -
- {error} -
- )} -
- -
- { - playBackSound("close_click.wav"); - onClose(); - }} - /> - { - playPressSound("save_click.wav"); - handleImport(); - }} - /> -
-
-
- ); -} diff --git a/src/components/modals/CustomizeModal.tsx b/src/components/modals/CustomizeModal.tsx deleted file mode 100644 index 228602e..0000000 --- a/src/components/modals/CustomizeModal.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; - -function isFilePath(value: string): boolean { - return value.startsWith("/") && !value.startsWith("/images/") && !value.startsWith("/panorama/"); -} - -async function resolvePath(value: string | undefined): Promise { - if (!value) return undefined; - if (isFilePath(value)) { - try { - return await TauriService.readScreenshotAsDataUrl(value); - } catch { - return value; - } - } - return value; -} - -export default function CustomizeModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - editionName, - currentTitleImage, - currentPanorama, - onSave, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - editionName: string; - currentTitleImage?: string; - currentPanorama?: string; - onSave: (updates: { titleImage?: string; panorama?: string }) => void; -}) { - const { t } = useTranslation(); - const [titleImage, setTitleImage] = useState(currentTitleImage || ""); - const [panorama, setPanorama] = useState(currentPanorama || ""); - const [focusIndex, setFocusIndex] = useState(0); - - useEffect(() => { - if (isOpen) { - setTitleImage(currentTitleImage || ""); - setPanorama(currentPanorama || ""); - setFocusIndex(0); - } - }, [isOpen, currentTitleImage, currentPanorama]); - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound("close_click.wav"); - onClose(); - } else if (e.key === "Enter") { - e.preventDefault(); - if (focusIndex === 4) { - playBackSound("close_click.wav"); - onClose(); - } else if (focusIndex === 5) { - handleSave(); - } - } else if (e.key === "ArrowDown" || e.key === "Tab") { - e.preventDefault(); - setFocusIndex((prev) => (prev + 1) % 6); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setFocusIndex((prev) => (prev - 1 + 6) % 6); - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, focusIndex, titleImage, panorama]); - - const handleSave = async () => { - playPressSound("save_click.wav"); - const [resolvedTitle, resolvedPanorama] = await Promise.all([ - resolvePath(titleImage || undefined), - resolvePath(panorama || undefined), - ]); - onSave({ - titleImage: resolvedTitle, - panorama: resolvedPanorama, - }); - onClose(); - }; - - const handlePickFile = async (field: "titleImage" | "panorama") => { - try { - const path = await TauriService.pickFile( - field === "titleImage" ? t("modals.customize.selectTitleImage") : t("modals.customize.selectPanorama"), - ["png", "jpg", "jpeg", "bmp"], - ); - if (path) { - if (field === "titleImage") setTitleImage(path); - else setPanorama(path); - playPressSound(); - } - } catch (e) { - if (e !== "CANCELED") console.error(e); - } - }; - - const handleReset = (field: "titleImage" | "panorama") => { - playPressSound(); - if (field === "titleImage") setTitleImage(""); - else setPanorama(""); - }; - - if (!isOpen) return null; - - const pickerSection = ( - field: "titleImage" | "panorama", - value: string, - idx: number, - resetIdx: number, - ) => ( -
- -
- - {value && ( - - )} -
- {value && ( -
- {t("modals.customize.preview")} { - (e.target as HTMLImageElement).style.display = "none"; - }} - /> - - {value.split("/").pop() || value} - -
- )} -
- ); - - return ( - -
-

- {t("modals.customize.title")} -

-

- {editionName} -

- -
- {pickerSection("titleImage", titleImage, 0, 1)} - {pickerSection("panorama", panorama, 2, 3)} -
- -
- - -
-
-
- ); -} diff --git a/src/components/modals/DownloadDlcModal.tsx b/src/components/modals/DownloadDlcModal.tsx deleted file mode 100644 index 60f61d9..0000000 --- a/src/components/modals/DownloadDlcModal.tsx +++ /dev/null @@ -1,393 +0,0 @@ -import { useState, useEffect, useRef, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; -interface DlcEntry { - name: string; - selected: boolean; -} - -export default function DownloadDlcModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - editionName, - instanceId, - officialDLC, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - editionName: string; - instanceId: string; - officialDLC: string; -}) { - const { t } = useTranslation(); - const [dlcList, setDlcList] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [downloading, setDownloading] = useState(false); - const [downloaded, setDownloaded] = useState([]); - const [dlcProgress, setDlcProgress] = useState>({}); - const [focusIndex, setFocusIndex] = useState(0); - const listRef = useRef(null); - const [branch, repoUrl] = officialDLC.includes(":") - ? [ - officialDLC.slice(0, officialDLC.indexOf(":")), - officialDLC.slice(officialDLC.indexOf(":") + 1), - ] - : ["main", officialDLC]; - - const fetchDlcs = useCallback(async () => { - setLoading(true); - setError(null); - try { - const [gitEntries, instancePath] = await Promise.all([ - TauriService.listGitDirectory(repoUrl, branch, ""), - TauriService.getInstancePath(instanceId), - ]); - - let existingDlcs: string[] = []; - try { - const dlcDirEntries = await TauriService.listDirectory( - instancePath + "/Windows64Media/DLC", - ); - existingDlcs = dlcDirEntries.filter((e) => e.is_dir).map((e) => e.name); - } catch { - existingDlcs = []; - } - - const folders = gitEntries - .filter((e) => e.is_dir) - .map((e) => e.name) - .sort(); - - setDlcList( - folders - .filter((name) => !existingDlcs.includes(name)) - .map((name) => ({ - name, - selected: false, - })), - ); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setLoading(false); - } - }, [repoUrl, branch, instanceId]); - - useEffect(() => { - if (isOpen) { - setDlcList([]); - setError(null); - setDownloading(false); - setDownloaded([]); - setDlcProgress({}); - setFocusIndex(0); - fetchDlcs(); - } - }, [isOpen, fetchDlcs]); - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - if (!downloading) { - playBackSound(); - onClose(); - } - return; - } - if (e.key === "ArrowDown") { - e.preventDefault(); - setFocusIndex((prev) => Math.min(prev + 1, dlcList.length - 1)); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setFocusIndex((prev) => Math.max(prev - 1, 0)); - } else if (e.key === "Enter" && !downloading) { - e.preventDefault(); - if (focusIndex >= 0 && focusIndex < dlcList.length) { - toggleDlc(dlcList[focusIndex].name); - } - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, dlcList, focusIndex, downloading, playBackSound, onClose]); - - useEffect(() => { - if (focusIndex >= 0 && listRef.current) { - const el = listRef.current.querySelector( - `[data-dlc-index="${focusIndex}"]`, - ) as HTMLElement; - if (el) { - el.scrollIntoView({ behavior: "smooth", block: "nearest" }); - } - } - }, [focusIndex]); - - const toggleDlc = (name: string) => { - playPressSound(); - setDlcList((prev) => - prev.map((d) => (d.name === name ? { ...d, selected: !d.selected } : d)), - ); - }; - - const selectAll = () => { - playPressSound(); - setDlcList((prev) => prev.map((d) => ({ ...d, selected: true }))); - }; - - const deselectAll = () => { - playPressSound(); - setDlcList((prev) => prev.map((d) => ({ ...d, selected: false }))); - }; - - const handleDownload = async () => { - const selected = dlcList.filter((d) => d.selected); - if (selected.length === 0) return; - playPressSound(); - setDownloading(true); - setDownloaded([]); - setDlcProgress({}); - const initialProgress: Record = {}; - selected.forEach((dlc) => { - initialProgress[dlc.name] = 0; - }); - setDlcProgress(initialProgress); - const unlisten = await TauriService.onDownloadProgress((data) => { - if (data.instanceId.startsWith("dlc:")) { - const name = data.instanceId.slice(4); - setDlcProgress((prev) => { - if (prev[name] === undefined) return prev; - return { ...prev, [name]: data.percent }; - }); - if (data.percent >= 100) { - setDownloaded((prev) => - prev.includes(name) ? prev : [...prev, name], - ); - } - } - }); - - const results = await Promise.allSettled( - selected.map((dlc) => - TauriService.downloadDlcFiles(instanceId, repoUrl, branch, dlc.name), - ), - ); - - unlisten(); - const succeeded: string[] = []; - for (let i = 0; i < results.length; i++) { - const r = results[i]; - if (r.status === "fulfilled") { - succeeded.push(selected[i].name); - } else { - setError( - t("modals.downloadDlc.failedToDownload", { - name: selected[i].name, - reason: - r.reason instanceof Error ? r.reason.message : String(r.reason), - }), - ); - } - } - setDownloaded(succeeded); - setDownloading(false); - }; - - const selectedCount = dlcList.filter((d) => d.selected).length; - if (!isOpen) return null; - return ( - -
-

- {t("modals.downloadDlc.title")} -

-

- {editionName} -

- - {loading && ( -
- {t("modals.downloadDlc.loading")} -
- )} - - {error && ( -
- {error} -
- )} - - {!loading && !error && dlcList.length === 0 && !downloading && ( -
- {t("modals.downloadDlc.noneFound")} -
- )} - - {!loading && dlcList.length > 0 && !downloading && ( - <> -
- - {t("modals.downloadDlc.available", { count: dlcList.length })} - -
- - -
-
- -
- {dlcList.map((dlc, i) => ( -
!downloading && toggleDlc(dlc.name)} - className={`flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors hover:bg-white/5 ${ - focusIndex === i ? "ring-1 ring-white bg-white/5" : "" - }`} - > -
- {dlc.selected && ( - - ✔ - - )} -
- - {dlc.name} - -
- ))} -
- - )} - - {downloading && ( -
- {dlcList - .filter((d) => d.selected) - .map((dlc) => { - const pct = dlcProgress[dlc.name] ?? 0; - const isDone = downloaded.includes(dlc.name); - return ( -
- - {isDone ? "100" : Math.floor(pct)}% - -
- - {dlc.name} - -
-
-
-
-
- ); - })} -
- )} - -
- {downloading && ( -
- {t("modals.downloadDlc.downloaded", { - downloaded: downloaded.length, - selected: selectedCount, - })} -
- )} -
- -
- {!downloading && selectedCount > 0 && ( - - )} - {downloading && downloaded.length === selectedCount && ( - - )} - -
-
- - ); -} diff --git a/src/components/modals/GameLogModal.tsx b/src/components/modals/GameLogModal.tsx deleted file mode 100644 index e8fb917..0000000 --- a/src/components/modals/GameLogModal.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; -const MAX_DISPLAY_LINES = 5000; -const WINE_CHANNEL = - /^\s*(?:[0-9a-fA-F]{1,8}:)?(err|fixme|warn|trace|debugstr):/; -function lineColor(line: string): string { - const match = WINE_CHANNEL.exec(line); - switch (match?.[1]) { - case "err": - return "#FF5555"; - case "fixme": - return "#FFFF55"; - case "warn": - return "#FFB347"; - case "trace": - return "#7FFF7F"; - case "debugstr": - return "#55FFFF"; - default: - return "#E0E0E0"; - } -} - -function LogActionButton({ - children, - onClick, - className = "", -}: { - children: React.ReactNode; - onClick: () => void; - className?: string; -}) { - const [hovered, setHovered] = useState(false); - return ( - - ); -} - -export default function GameLogModal({ - isOpen, - log, - onClose, - playBackSound, -}: { - isOpen: boolean; - log: string | null; - onClose: () => void; - playBackSound: () => void; -}) { - const { t } = useTranslation(); - const scrollRef = useRef(null); - const [feedback, setFeedback] = useState(""); - const lines = useMemo(() => (log ?? "").split("\n"), [log]); - const truncated = lines.length > MAX_DISPLAY_LINES; - const visibleLines = truncated ? lines.slice(-MAX_DISPLAY_LINES) : lines; - useEffect(() => { - if (isOpen) { - setFeedback(""); - if (scrollRef.current) { - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; - } - } - }, [isOpen, log]); - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound(); - onClose(); - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, onClose, playBackSound]); - - if (!isOpen) return null; - const handleSave = async () => { - if (!log) return; - try { - const path = await TauriService.saveFileDialog( - t("modals.gameLog.saveDialog"), - "game-log.txt", - ["txt", "log"], - ); - if (!path) return; - await TauriService.writeBinaryFile(path, new TextEncoder().encode(log)); - setFeedback(t("modals.gameLog.saved")); - } catch (e) { - console.error(e); - setFeedback(t("modals.gameLog.failedToSave")); - } - }; - - const handleCopy = async () => { - if (!log) return; - try { - await navigator.clipboard.writeText(log); - setFeedback(t("modals.gameLog.copied")); - } catch (e) { - console.error(e); - setFeedback(t("modals.gameLog.failedToCopy")); - } - }; - - return ( - { - playBackSound(); - onClose(); - }} - > - e.stopPropagation()} - className="flex flex-col w-[640px] max-w-[92vw] max-h-[85vh] p-5 font-[var(--font-base)] mc-options-bg" - > -

- {t("modals.gameLog.title")} -

- - {truncated && ( -

- {t("modals.gameLog.showingLast", { - shown: MAX_DISPLAY_LINES, - total: lines.length, - })} -

- )} - -
-
- {visibleLines.map((line, i) => ( - - {line} - {"\n"} - - ))} -
-
- -
- - {t("modals.gameLog.saveAsFile")} - - - {t("modals.gameLog.copy")} - - { - playBackSound(); - onClose(); - }} - className="flex-1" - > - {t("modals.gameLog.close")} - -
- {feedback && ( -

- {feedback} -

- )} -
-
- ); -} diff --git a/src/components/modals/ImportWorldModal.tsx b/src/components/modals/ImportWorldModal.tsx deleted file mode 100644 index 4b1007f..0000000 --- a/src/components/modals/ImportWorldModal.tsx +++ /dev/null @@ -1,360 +0,0 @@ -import { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; -export default function ImportWorldModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - targetInstanceId, - targetInstanceName, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - targetInstanceId: string; - targetInstanceName: string; -}) { - const { t } = useTranslation(); - const [status, setStatus] = useState(""); - const [error, setError] = useState(""); - const [isImporting, setIsImporting] = useState(false); - useEffect(() => { - if (!isOpen) { - setStatus(""); - setError(""); - setIsImporting(false); - } - }, [isOpen]); - - const handleImportMs = async () => { - if (!targetInstanceId) return; - playPressSound(); - setIsImporting(true); - setError(""); - setStatus(t("modals.importWorld.selectingSource")); - try { - setStatus(t("modals.importWorld.selectingMsFile")); - const picked = await TauriService.pickFile("Select saveData.ms", [ - "*.ms", - "*", - ]); - if (!picked) { - setIsImporting(false); - return; - } - const worldName = deriveWorldName(picked); - setStatus(t("modals.importWorld.copyingLceSave")); - - const instancePath = await TauriService.getInstancePath(targetInstanceId); - const saveDir = `${instancePath}/Windows64/GameHDD/${worldName}`; - await TauriService.importWorld(picked, `${saveDir}/saveData.ms`); - - setStatus( - t("modals.importWorld.worldImported", { name: targetInstanceName }), - ); - setTimeout(() => { - onClose(); - }, 2000); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsImporting(false); - } - }; - - const handleImportXbox = async () => { - if (!targetInstanceId) return; - playPressSound(); - setIsImporting(true); - setError(""); - setStatus(t("modals.importWorld.selectingSource")); - try { - setStatus(t("modals.importWorld.selectingXboxSave")); - const picked = await TauriService.pickFile( - "Select Xbox 360 Minecraft save", - ["*.bin", "*"], - ); - if (!picked) { - setIsImporting(false); - return; - } - setStatus(t("modals.importWorld.convertingXbox")); - const instancePath = await TauriService.getInstancePath(targetInstanceId); - const gameHdd = `${instancePath}/Windows64/GameHDD`; - await TauriService.importLceSave(picked, gameHdd); - setStatus( - t("modals.importWorld.xboxConverted", { name: targetInstanceName }), - ); - setTimeout(() => { - onClose(); - }, 2000); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsImporting(false); - } - }; - - const handleImportPs3 = async () => { - if (!targetInstanceId) return; - playPressSound(); - setIsImporting(true); - setError(""); - setStatus(t("modals.importWorld.selectingSource")); - try { - setStatus(t("modals.importWorld.selectingPs3Folder")); - const picked = await TauriService.pickFolder(); - if (!picked) { - setIsImporting(false); - return; - } - setStatus(t("modals.importWorld.convertingPs3")); - const instancePath = await TauriService.getInstancePath(targetInstanceId); - const gameHdd = `${instancePath}/Windows64/GameHDD`; - await TauriService.importLceSave(picked, gameHdd); - setStatus( - t("modals.importWorld.ps3Converted", { name: targetInstanceName }), - ); - setTimeout(() => { - onClose(); - }, 2000); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsImporting(false); - } - }; - - const handleImportJava = async () => { - if (!targetInstanceId) return; - playPressSound(); - setIsImporting(true); - setError(""); - setStatus(t("modals.importWorld.selectingSource")); - try { - setStatus(t("modals.importWorld.selectingJavaFolder")); - const picked = await TauriService.pickFolder(); - if (!picked) { - setIsImporting(false); - return; - } - const worldName = deriveWorldName(picked); - setStatus(t("modals.importWorld.convertingJava")); - const instancePath = await TauriService.getInstancePath(targetInstanceId); - const saveDir = `${instancePath}/Windows64/GameHDD/${worldName}`; - await TauriService.javaToLce(picked, `${saveDir}/saveData.ms`); - setStatus( - t("modals.importWorld.javaConverted", { name: targetInstanceName }), - ); - setTimeout(() => { - onClose(); - }, 2000); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsImporting(false); - } - }; - - const handleExportJava = async () => { - if (!targetInstanceId) return; - playPressSound(); - setIsImporting(true); - setError(""); - setStatus(t("modals.importWorld.selectingSource")); - try { - setStatus(t("modals.importWorld.selectingMsFile")); - const picked = await TauriService.pickFile("Select saveData.ms", [ - "*.ms", - "*", - ]); - if (!picked) { - setIsImporting(false); - return; - } - setStatus(t("modals.importWorld.selectingOutputFolder")); - const outputFolder = await TauriService.pickFolder(); - if (!outputFolder) { - setIsImporting(false); - return; - } - setStatus(t("modals.importWorld.convertingLceToJava")); - await TauriService.lceToJava(picked, outputFolder); - setStatus( - t("modals.importWorld.javaExported", { path: outputFolder }), - ); - setTimeout(() => { - onClose(); - }, 2000); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - setStatus(""); - setIsImporting(false); - } - }; - - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound(); - if (isImporting) return; - onClose(); - } - }; - - useEffect(() => { - if (!isOpen) return; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, isImporting]); - - if (!isOpen) return null; - - return ( - -
- {!isImporting ? ( - <> -

- Import World -

-

- Import into:{" "} - {targetInstanceName} -

- -

- Import an existing .ms save file: -

- - -

- Convert an Xbox 360 or PS3 save: -

-
- - -
- -

- Java Edition world conversion: -

-
- - -
- - {error && ( -
- {error} -
- )} - - - - ) : ( - <> -

- Importing World -

-
-
-

- {status} -

-
- {error && ( -
- {error} -
- )} - - )} -
- - ); -} - -function deriveWorldName(inputPath: string): string { - const name = - inputPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || - "ImportedWorld"; - return name.replace(/[^a-zA-Z0-9_\- ]/g, "_").slice(0, 64); -} diff --git a/src/components/modals/OptionsModal.tsx b/src/components/modals/OptionsModal.tsx deleted file mode 100644 index 55ddad7..0000000 --- a/src/components/modals/OptionsModal.tsx +++ /dev/null @@ -1,517 +0,0 @@ -import { useState, useEffect, useMemo, useRef, type RefObject } from "react"; -import { useTranslation } from "react-i18next"; -import { TauriService } from "../../services/TauriService"; -import { - parseSchema, - mergeValues, - defaultValues, - computeEffects, - buildArgs, - type ArgsSchema, - type SchemaOption, -} from "../../utils/argsSchema"; - -export default function OptionsModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - instanceId, - instanceName, - savedValues, - onSave, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - instanceId: string; - instanceName: string; - savedValues?: Record; - onSave: ( - instanceId: string, - values: Record, - args: string[], - ) => void; -}) { - const { t } = useTranslation(); - const [schema, setSchema] = useState(null); - const [values, setValues] = useState>({}); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - const [focusIndex, setFocusIndex] = useState(0); - const rowRefs = useRef<(HTMLElement | null)[]>([]); - const inputRefs = useRef<(HTMLElement | null)[]>([]); - const resetRef = useRef(null); - const cancelRef = useRef(null); - const saveRef = useRef(null); - - useEffect(() => { - if (!isOpen) return; - let cancelled = false; - setLoading(true); - setError(null); - setSchema(null); - setValues({}); - setFocusIndex(0); - TauriService.getInstanceArgsSchema(instanceId) - .then((raw) => { - if (cancelled) return; - if (!raw) { - setError(t("modals.options.noSchema")); - setLoading(false); - return; - } - const parsed = parseSchema(raw); - if (!parsed) { - setError(t("modals.options.invalidSchema")); - setLoading(false); - return; - } - setSchema(parsed); - setValues(mergeValues(parsed, savedValues)); - setLoading(false); - }) - .catch((e) => { - if (cancelled) return; - setError(e instanceof Error ? e.message : String(e)); - setLoading(false); - }); - return () => { - cancelled = true; - }; - }, [isOpen, instanceId, savedValues]); - - const effects = useMemo( - () => (schema ? computeEffects(schema, values) : {}), - [schema, values], - ); - - const visibleOptions = useMemo( - () => - schema - ? schema.options.filter((o) => !effects[o.id]?.hidden) - : ([] as SchemaOption[]), - [schema, effects], - ); - - const optionOrder = useMemo( - () => visibleOptions.map((o) => o.id), - [visibleOptions], - ); - - useEffect(() => { - setFocusIndex((prev) => Math.min(prev, optionOrder.length + 2)); - }, [optionOrder.length]); - - const sections = useMemo(() => { - if (!schema) - return { - sections: [] as { - title: string; - description?: string; - options: SchemaOption[]; - }[], - general: [] as SchemaOption[], - }; - const byGroup = new Map(); - const general: SchemaOption[] = []; - const declared = new Set(schema.groups.map((g) => g.id)); - for (const option of visibleOptions) { - if (option.group && declared.has(option.group)) { - const list = byGroup.get(option.group); - if (list) list.push(option); - else byGroup.set(option.group, [option]); - } else { - general.push(option); - } - } - const sections = schema.groups - .map((group) => ({ - title: group.title, - description: group.description, - options: byGroup.get(group.id) ?? ([] as SchemaOption[]), - })) - .filter((s) => s.options.length > 0); - return { sections, general }; - }, [schema, visibleOptions]); - - const handleReset = () => { - playPressSound(); - if (!schema) return; - setValues(defaultValues(schema)); - }; - - const handleSave = () => { - if (!schema) return; - playPressSound("save_click.wav"); - const finalValues = { ...values }; - onSave( - instanceId, - finalValues, - buildArgs(schema, finalValues, computeEffects(schema, finalValues)), - ); - onClose(); - }; - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - const activeTag = document.activeElement?.tagName; - if ( - activeTag === "INPUT" || - activeTag === "SELECT" || - activeTag === "TEXTAREA" - ) { - if (e.key === "Escape") { - playBackSound(); - onClose(); - } - return; - } - const total = optionOrder.length + 3; - if (e.key === "Escape") { - playBackSound(); - onClose(); - } else if (e.key === "ArrowDown" || e.key === "Tab") { - e.preventDefault(); - setFocusIndex((prev) => (prev + 1) % total); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setFocusIndex((prev) => (prev - 1 + total) % total); - } else if (e.key === "Enter") { - e.preventDefault(); - if (focusIndex < optionOrder.length) { - const id = optionOrder[focusIndex]; - const option = schema?.options.find((o) => o.id === id); - if (!option) return; - const effect = effects[id]; - if (option.type === "boolean") { - if (!effect?.disabled) { - setValues((prev) => ({ ...prev, [id]: !prev[id] })); - } - } else { - const input = inputRefs.current[focusIndex]; - if (input) input.focus(); - } - } else if (focusIndex === optionOrder.length) { - handleReset(); - } else if (focusIndex === optionOrder.length + 1) { - playBackSound(); - onClose(); - } else { - handleSave(); - } - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [ - isOpen, - optionOrder, - focusIndex, - schema, - values, - effects, - playPressSound, - playBackSound, - onClose, - ]); - - useEffect(() => { - if (!isOpen) return; - if (focusIndex < optionOrder.length) { - rowRefs.current[focusIndex]?.focus(); - } else if (focusIndex === optionOrder.length) { - resetRef.current?.focus(); - } else if (focusIndex === optionOrder.length + 1) { - cancelRef.current?.focus(); - } else { - saveRef.current?.focus(); - } - }, [isOpen, focusIndex, optionOrder]); - - if (!isOpen) return null; - - const flatIndex = (optionId: string) => optionOrder.indexOf(optionId); - const titleDesc = (option: SchemaOption) => ( -
-
- {option.title} -
- {option.description && ( -
- {option.description} -
- )} -
- ); - - const control = (option: SchemaOption, index: number, disabled: boolean) => { - const value = values[option.id]; - switch (option.type) { - case "boolean": - return null; - case "int": - case "number": - return ( -
- { - inputRefs.current[index] = el; - }} - type="number" - disabled={disabled} - min={option.min} - max={option.max} - step={option.step ?? (option.type === "int" ? 1 : "any")} - value={typeof value === "number" ? value : ""} - onChange={(e) => { - const raw = e.target.value; - setValues((prev) => ({ - ...prev, - [option.id]: raw === "" ? "" : Number(raw), - })); - }} - onFocus={() => setFocusIndex(index)} - className={`mc-textinput w-full h-10 px-3 text-white text-sm outline-none text-center font-[var(--font-base)] [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none ${ - disabled ? "opacity-40 cursor-not-allowed" : "" - }`} - style={{ imageRendering: "pixelated" }} - /> -
- ); - case "string": - return ( -
- { - inputRefs.current[index] = el; - }} - type="text" - disabled={disabled} - placeholder={option.placeholder} - value={typeof value === "string" ? value : ""} - onChange={(e) => { - setValues((prev) => ({ ...prev, [option.id]: e.target.value })); - }} - onFocus={() => setFocusIndex(index)} - className={`mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)] ${ - disabled ? "opacity-40 cursor-not-allowed" : "" - }`} - style={{ imageRendering: "pixelated" }} - /> -
- ); - case "choice": - return ( - - ); - } - }; - - const renderOption = (option: SchemaOption) => { - const index = flatIndex(option.id); - const effect = effects[option.id]; - const disabled = !!effect?.disabled; - const isFocused = focusIndex === index; - if (option.type === "boolean") { - return ( - - ); - } - return ( -
{ - rowRefs.current[index] = el; - }} - tabIndex={-1} - className={`w-full flex items-center gap-3 px-3 py-2 outline-none border-2 ${ - isFocused ? "border-[#FFFF55] bg-black/10" : "border-transparent" - } ${disabled ? "opacity-50" : ""}`} - > -
- {control(option, index, disabled)} - {titleDesc(option)} -
-
- ); - }; - - const actionButton = ( - ref: RefObject, - index: number, - label: string, - onClick: () => void, - danger?: boolean, - ) => ( - - ); - - return ( -
{ - if (e.target === e.currentTarget) { - playBackSound(); - onClose(); - } - }} - > -
-

- {t("modals.options.title")} -

-

- {instanceName} -

- - {loading ? ( -
-
-

- {t("modals.options.loading")} -

-
- ) : error ? ( -
-

- {error} -

-
- {actionButton(cancelRef, optionOrder.length + 1, t("modals.options.ok"), () => { - playBackSound(); - onClose(); - })} -
-
- ) : schema ? ( - <> -
- {sections.sections.map((section) => ( -
-

- {section.title} -

- {section.description && ( -

- {section.description} -

- )} - {section.options.map(renderOption)} -
- ))} - {sections.general.length > 0 && ( -
-

- {t("modals.options.general")} -

- {sections.general.map(renderOption)} -
- )} -
- -
- {actionButton( - resetRef, - optionOrder.length, - t("modals.options.reset"), - handleReset, - true, - )} - {actionButton(cancelRef, optionOrder.length + 1, t("modals.options.cancel"), () => { - playBackSound(); - onClose(); - })} - {actionButton( - saveRef, - optionOrder.length + 2, - t("modals.options.save"), - handleSave, - )} -
- - ) : null} -
-
- ); -} diff --git a/src/components/modals/PlaytimeModal.tsx b/src/components/modals/PlaytimeModal.tsx deleted file mode 100644 index d407283..0000000 --- a/src/components/modals/PlaytimeModal.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { useState, useEffect, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { - TauriService, - PlaytimeResponse, - PlaytimeDayEntry, -} from "../../services/TauriService"; -function formatTime(seconds: number): string { - const h = Math.floor(seconds / 3600); - const m = Math.floor((seconds % 3600) / 60); - const s = seconds % 60; - if (h > 0) return `${h}h ${m}m ${s}s`; - if (m > 0) return `${m}m ${s}s`; - return `${s}s`; -} - -function formatShort(seconds: number): string { - const h = Math.floor(seconds / 3600); - const m = Math.floor((seconds % 3600) / 60); - if (h > 0) return `${h}h`; - if (m > 0) return `${m}m`; - return `${seconds}s`; -} - -function PlaytimeChart({ data }: { data: PlaytimeDayEntry[] }) { - const canvasRef = useRef(null); - useEffect(() => { - const canvas = canvasRef.current; - if (!canvas || data.length === 0) return; - const ctx = canvas.getContext("2d"); - if (!ctx) return; - const dpr = window.devicePixelRatio || 1; - const w = 320; - const h = 120; - canvas.width = w * dpr; - canvas.height = h * dpr; - canvas.style.width = `${w}px`; - canvas.style.height = `${h}px`; - ctx.scale(dpr, dpr); - ctx.clearRect(0, 0, w, h); - const maxSecs = Math.max(...data.map((d) => d.seconds), 1); - const pad = { top: 8, bottom: 20, left: 6, right: 6 }; - const chartW = w - pad.left - pad.right; - const chartH = h - pad.top - pad.bottom; - const barW = Math.min(28, (chartW - (data.length - 1) * 4) / data.length); - const gap = (chartW - barW * data.length) / (data.length - 1); - data.forEach((entry, i) => { - const x = pad.left + i * (barW + gap); - const barH = (entry.seconds / maxSecs) * chartH; - const y = pad.top + chartH - barH; - ctx.fillStyle = "#FFFF55"; - ctx.fillRect(x, y, barW, barH); - ctx.fillStyle = "#FFFFFF"; - ctx.font = "9px Mojangles, monospace"; - ctx.textAlign = "center"; - ctx.fillText(formatShort(entry.seconds), x + barW / 2, y - 3); - ctx.fillStyle = "#AAAAAA"; - ctx.fillText(entry.label, x + barW / 2, h - 4); - }); - }, [data]); - - return ; -} - -export default function PlaytimeModal({ - isOpen, - onClose, - instanceId, - instanceName, - playBackSound, -}: { - isOpen: boolean; - onClose: () => void; - instanceId: string; - instanceName: string; - playBackSound: (s?: string) => void; -}) { - const { t } = useTranslation(); - const [playtime, setPlaytime] = useState(null); - const [dailyData, setDailyData] = useState([]); - const [loading, setLoading] = useState(false); - const [chartDays, setChartDays] = useState(7); - useEffect(() => { - if (!isOpen) { - setPlaytime(null); - setDailyData([]); - return; - } - setLoading(true); - Promise.all([ - TauriService.getPlaytime(instanceId), - TauriService.getPlaytimeDaily(instanceId, chartDays), - ]) - .then(([pt, daily]) => { - setPlaytime(pt); - setDailyData(daily); - }) - .catch(console.error) - .finally(() => setLoading(false)); - }, [isOpen, instanceId, chartDays]); - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound("close_click.wav"); - onClose(); - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, onClose, playBackSound]); - - if (!isOpen) return null; - return ( - -
-

- {t("modals.playtime.title")} -

- -

- {instanceName} -

- - {loading ? ( -
- {t("modals.playtime.loading")} -
- ) : playtime ? ( - <> -
-
- - {t("modals.playtime.total")} - - - {formatTime(playtime.totalSeconds)} - -
-
- - {t("modals.playtime.thisWeek")} - - - {formatTime(playtime.weekSeconds)} - -
-
- - {t("modals.playtime.today")} - - - {formatTime(playtime.daySeconds)} - -
-
- - {dailyData.length > 0 && ( -
-
- - {t("modals.playtime.dailyBreakdown")} - -
- {[3, 7, 14].map((d) => ( - - ))} -
-
-
- -
-
- )} - - ) : ( -
- {t("modals.playtime.failedToLoad")} -
- )} - - -
-
- ); -} diff --git a/src/components/modals/SetUidModal.tsx b/src/components/modals/SetUidModal.tsx deleted file mode 100644 index adeb3b7..0000000 --- a/src/components/modals/SetUidModal.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { motion } from "framer-motion"; -import { TauriService } from "../../services/TauriService"; -import type { Edition } from "../../types/edition"; - -export default function SetUidModal({ - isOpen, - onClose, - playPressSound, - playBackSound, - instances, - installedVersions, - targetInstanceId, -}: { - isOpen: boolean; - onClose: () => void; - playPressSound: (s?: string) => void; - playBackSound: (s?: string) => void; - instances: Edition[]; - installedVersions: string[]; - targetInstanceId: string; -}) { - const { t } = useTranslation(); - const [mode, setMode] = useState<"manual" | "copy">("manual"); - const [uid, setUid] = useState("0xFF02F0C87E8AC1F2"); - const [selectedInstance, setSelectedInstance] = useState(""); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); - const [error, setError] = useState(""); - const [focusIndex, setFocusIndex] = useState(0); - - useEffect(() => { - if (!isOpen) { - setMode("manual"); - setUid("0xFF02F0C87E8AC1F2"); - setSelectedInstance(""); - setError(""); - setFocusIndex(0); - setIsDropdownOpen(false); - } else if (targetInstanceId) { - (async () => { - try { - const targetPath = await TauriService.getInstancePath(targetInstanceId); - const data = await TauriService.readBinaryFile(`${targetPath}/uid.dat`); - const currentUid = new TextDecoder().decode(data); - if (currentUid.trim()) { - setUid(currentUid); - } else { - setUid("0xFF02F0C87E8AC1F2"); - } - } catch (e) { - setUid("0xFF02F0C87E8AC1F2"); - } - })(); - } - }, [isOpen, targetInstanceId]); - - const validInstances = instances.filter((i: Edition) => installedVersions.includes(i.instanceId) && i.instanceId !== targetInstanceId); - const handleSave = async () => { - playPressSound("save_click.wav"); - try { - let finalUid = uid; - if (mode === "copy") { - if (!selectedInstance) { - setError(t("modals.setUid.selectToCopy")); - return; - } - const sourcePath = await TauriService.getInstancePath(selectedInstance); - try { - const sourceData = await TauriService.readBinaryFile(`${sourcePath}/uid.dat`); - finalUid = new TextDecoder().decode(sourceData); - } catch (e) { - setError(t("modals.setUid.sourceNoUid")); - return; - } - } - - if (!finalUid) { - setError(t("modals.setUid.uidEmpty")); - return; - } - - const encodedUid = new TextEncoder().encode(finalUid); - const targetPath = await TauriService.getInstancePath(targetInstanceId); - await TauriService.writeBinaryFile(`${targetPath}/uid.dat`, encodedUid); - - onClose(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - } - }; - - useEffect(() => { - if (!isOpen) return; - const handleKey = (e: KeyboardEvent) => { - if (e.key === "Escape") { - playBackSound("close_click.wav"); - onClose(); - } else if (e.key === "ArrowDown" || e.key === "Tab") { - e.preventDefault(); - setFocusIndex((prev) => (prev + 1) % 5); - } else if (e.key === "ArrowUp") { - e.preventDefault(); - setFocusIndex((prev) => (prev - 1 + 5) % 5); - } else if (e.key === "Enter") { - e.preventDefault(); - if (focusIndex === 0) { - playPressSound(); - setMode("manual"); - } else if (focusIndex === 1) { - playPressSound(); - setMode("copy"); - } else if (focusIndex === 2 && mode === "copy") { - playPressSound(); - setIsDropdownOpen(!isDropdownOpen); - } else if (focusIndex === 3) { - playBackSound("close_click.wav"); - onClose(); - } else if (focusIndex === 4) { - handleSave(); - } - } - }; - window.addEventListener("keydown", handleKey); - return () => window.removeEventListener("keydown", handleKey); - }, [isOpen, focusIndex, mode, uid, selectedInstance, isDropdownOpen]); - - if (!isOpen) return null; - - return ( - -
-

- {t("modals.setUid.title")} -

- -
- - -
- -
- {mode === "manual" ? ( -
- -
- setUid(e.target.value)} - onFocus={() => setFocusIndex(2)} - placeholder="0xFF02F0C87E8AC1F2" - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-center" - style={{ imageRendering: "pixelated", filter: focusIndex === 2 ? 'brightness(1.2)' : 'none' }} - /> -
-
- ) : ( -
- - -
{ playPressSound(); setIsDropdownOpen(!isDropdownOpen); }} - onFocus={() => { setFocusIndex(2); setIsDropdownOpen(false); }} - tabIndex={0} - className={`w-full h-10 px-3 bg-black/40 border-2 ${focusIndex === 2 ? 'border-white' : 'border-[#373737]'} flex items-center justify-between text-white text-base outline-none font-[var(--font-base)] cursor-pointer`} - style={{ imageRendering: "pixelated", filter: focusIndex === 2 ? 'brightness(1.2)' : 'none' }} - > - - {selectedInstance - ? (() => { - const i = validInstances.find((inst: Edition) => inst.instanceId === selectedInstance); - return i ? `${i.name} ${i.selectedBranch ? `(${i.selectedBranch})` : ""}` : t("modals.setUid.selectPlaceholder"); - })() - : t("modals.setUid.selectPlaceholder")} - - ▼ -
- - {isDropdownOpen && validInstances.length > 0 && ( -
- {validInstances.map((i: Edition) => ( -
{ - playPressSound(); - setSelectedInstance(i.instanceId); - setIsDropdownOpen(false); - }} - className="px-3 py-2 text-white text-sm cursor-pointer truncate font-[var(--font-base)]" - > - {i.name} {i.selectedBranch ? `(${i.selectedBranch})` : ""} -
- ))} -
- )} - - {validInstances.length === 0 && ( -

{t("modals.setUid.noInstances")}

- )} -
- )} - - {error && ( -
- {error} -
- )} -
- -
- - -
-
-
- ); -} \ No newline at end of file diff --git a/src/components/plugins/PluginViewContainer.tsx b/src/components/plugins/PluginViewContainer.tsx deleted file mode 100644 index 13857d0..0000000 --- a/src/components/plugins/PluginViewContainer.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { Component, type ReactNode, type ErrorInfo } from "react"; -import { motion } from "framer-motion"; -import type { PluginViewRegistration } from "../../plugins/types"; -import { PluginManager } from "../../plugins/PluginManager"; -interface Props { - registry: PluginViewRegistration; -} - -interface State { - hasError: boolean; - error: Error | null; -} - -class PluginErrorBoundary extends Component< - { children: ReactNode; pluginId: string }, - State -> { - constructor(props: { children: ReactNode; pluginId: string }) { - super(props); - this.state = { hasError: false, error: null }; - } - - static getDerivedStateFromError(error: Error): State { - return { hasError: true, error }; - } - - componentDidCatch(error: Error, info: ErrorInfo): void { - console.error(`[Plugin ${this.props.pluginId}] Render error:`, error, info); - } - - render(): ReactNode { - if (this.state.hasError) { - return ( -
- Plugin Error - - {this.state.error?.message ?? "Unknown error"} - -
- ); - } - return this.props.children; - } -} - -export function PluginViewContainer({ registry }: Props) { - const pm = PluginManager.instance; - const plugin = pm.plugins.get(registry.pluginId); - if (!plugin) return null; - let Component: React.ComponentType>; - try { - Component = registry.factory(plugin.api); - } catch (err) { - console.error(`[Plugin] Error creating component for ${registry.id}:`, err); - return ( -
- Failed to create view -
- ); - } - - return ( - - - - - - ); -} diff --git a/src/components/views/ArcEditorView.tsx b/src/components/views/ArcEditorView.tsx deleted file mode 100644 index 1b6feff..0000000 --- a/src/components/views/ArcEditorView.tsx +++ /dev/null @@ -1,748 +0,0 @@ -import { useState, useRef, useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { motion, AnimatePresence } from "framer-motion"; -import { useUI, useAudio, useConfig } from "../../context/LauncherContext"; -import { ArcService } from "../../services/ArcService"; -import { ArcFile, ArcEntry, LocFile, LocLanguage } from "../../types/arc"; -import { TauriService } from "../../services/TauriService"; - -export const ArcEditorView: React.FC = () => { - const { t } = useTranslation(); - const { setActiveView } = useUI(); - const { playPressSound, playBackSound } = useAudio(); - const { animationsEnabled } = useConfig(); - const [arc, setArc] = useState(null); - const [openedPath, setOpenedPath] = useState(null); - const [loc, setLoc] = useState(null); - const [activeTab, setActiveTab] = useState<"arc" | "loc">("arc"); - const [searchTerm, setSearchTerm] = useState(""); - const [selectedEntryIdx, setSelectedEntryIdx] = useState(null); - const [selectedLocLangIdx, setSelectedLocLangIdx] = useState(0); - const [notification, setNotification] = useState<{ message: string, type: "success" | "error" } | null>(null); - const [isAddModalOpen, setIsAddModalOpen] = useState(false); - const [isReplaceModalOpen, setIsReplaceModalOpen] = useState(false); - const [isRenameModalOpen, setIsRenameModalOpen] = useState(false); - const [isLocEditModalOpen, setIsLocEditModalOpen] = useState<{ langIdx: number, strIdx: number, isNew: boolean } | null>(null); - const injectInputRef = useRef(null); - const replaceInputRef = useRef(null); - - const filteredEntries = useMemo(() => { - if (!arc) return []; - return arc.entries.map((e, i) => ({ ...e, originalIdx: i })) - .filter(e => e.filename.toLowerCase().includes(searchTerm.toLowerCase())); - }, [arc, searchTerm]); - - const currentLocLang = useMemo(() => { - if (!loc) return null; - return loc.languages[selectedLocLangIdx] || null; - }, [loc, selectedLocLangIdx]); - - const filteredLocStrings = useMemo(() => { - if (!currentLocLang) return []; - return currentLocLang.strings.map((s, i) => ({ ...s, originalIdx: i })) - .filter(s => (s.key?.toLowerCase().includes(searchTerm.toLowerCase()) || s.value.toLowerCase().includes(searchTerm.toLowerCase()))); - }, [currentLocLang, searchTerm]); - - const showNotification = (message: string, type: "success" | "error" = "success") => { - setNotification({ message, type }); - setTimeout(() => setNotification(null), 3000); - }; - - const handleFileLoad = async () => { - try { - const path = await TauriService.pickFile(t("arcEditor.openArc"), ["arc"]); - if (!path) return; - playPressSound(); - const bytes = await TauriService.readBinaryFile(path); - const parsed = await ArcService.readARC(bytes.buffer as ArrayBuffer); - parsed.name = path.split(/[\/\\]/).pop() || "archive.arc"; - setArc(parsed); - setOpenedPath(path); - - const locEntry = parsed.entries.find(entry => entry.filename.toLowerCase() === "languages.loc"); - if (locEntry) { - try { - const parsedLoc = ArcService.parseLOC(locEntry.data); - setLoc(parsedLoc); - } catch (err) { - console.warn("Could not parse languages.loc", err); - setLoc(null); - } - } else { - setLoc(null); - } - setSelectedEntryIdx(null); - showNotification(t("arcEditor.loaded", { name: parsed.name })); - } catch (err: unknown) { - if (err !== "CANCELED") { - console.error("Failed to parse ARC", err); - showNotification(t("arcEditor.failedToParse"), "error"); - } - } - }; - - const handleSaveArc = async () => { - if (!arc) return; - playPressSound(); - const buffer = ArcService.serializeARC(arc); - const data = new Uint8Array(buffer); - - try { - let targetPath = openedPath; - if (!targetPath) { - targetPath = await TauriService.saveFileDialog(t("arcEditor.saveArcDialog"), arc.name || "archive.arc", ["arc"]); - } - - if (targetPath) { - await TauriService.writeBinaryFile(targetPath, data); - setOpenedPath(targetPath); - showNotification(t("arcEditor.arcSaved")); - } - } catch (err: unknown) { - if (err !== "CANCELED") showNotification(t("arcEditor.saveFailed"), "error"); - } - }; - - const handleExtractEntry = async (entry: ArcEntry) => { - try { - const fileName = entry.filename.split("/").pop() || "asset"; - const path = await TauriService.saveFileDialog(t("arcEditor.exportAssetDialog"), fileName, []); - if (!path) return; - playPressSound(); - await TauriService.writeBinaryFile(path, entry.data); - showNotification(t("arcEditor.extracted", { name: entry.filename })); - } catch (err: unknown) { - if (err !== "CANCELED") showNotification(t("arcEditor.extractionFailed"), "error"); - } - }; - - const handleDeleteEntry = (idx: number) => { - if (!arc) return; - playBackSound(); - const name = arc.entries[idx].filename; - const newEntries = [...arc.entries]; - newEntries.splice(idx, 1); - setArc({ ...arc, entries: newEntries }); - setSelectedEntryIdx(null); - showNotification(t("arcEditor.deleted", { name })); - }; - - const handleSaveLocToArc = () => { - if (!loc || !arc) return; - playPressSound(); - const data = ArcService.serializeLOC(loc); - const locIdx = arc.entries.findIndex(e => e.filename.toLowerCase() === "languages.loc"); - const newEntries = [...arc.entries]; - if (locIdx >= 0) { - newEntries[locIdx] = { ...newEntries[locIdx], data, size: data.length }; - showNotification(t("arcEditor.locUpdatedInArchive")); - } else { - newEntries.push({ filename: "languages.loc", ptr: 0, size: data.length, isCompressed: false, data }); - showNotification(t("arcEditor.locAddedToArchive")); - } - setArc({ ...arc, entries: newEntries }); - }; - - const handleAddEntry = async (e: React.ChangeEvent) => { - if (!arc) return; - const file = e.target.files?.[0]; - if (!file) return; - playPressSound(); - const buffer = await file.arrayBuffer(); - const data = new Uint8Array(buffer); - const newEntry: ArcEntry = { - filename: file.name, - ptr: 0, - size: data.length, - isCompressed: false, - data - }; - setArc({ ...arc, entries: [...arc.entries, newEntry] }); - e.target.value = ""; - showNotification(t("arcEditor.entryAdded")); - setIsAddModalOpen(false); - }; - - const handleReplaceEntry = async (e: React.ChangeEvent) => { - if (!arc || selectedEntryIdx === null) return; - const file = e.target.files?.[0]; - if (!file) return; - playPressSound(); - const buffer = await file.arrayBuffer(); - const data = new Uint8Array(buffer); - const newEntries = [...arc.entries]; - newEntries[selectedEntryIdx] = { ...newEntries[selectedEntryIdx], data, size: data.length }; - setArc({ ...arc, entries: newEntries }); - e.target.value = ""; - showNotification(t("arcEditor.entryReplaced")); - setIsReplaceModalOpen(false); - }; - - const handleRenameEntry = (newPath: string, isCompressed: boolean) => { - if (!arc || selectedEntryIdx === null) return; - playPressSound(); - const newEntries = [...arc.entries]; - newEntries[selectedEntryIdx] = { ...newEntries[selectedEntryIdx], filename: newPath, isCompressed }; - setArc({ ...arc, entries: newEntries }); - setIsRenameModalOpen(false); - showNotification(t("arcEditor.entryRenamed")); - }; - - const handleLocStringEdit = (langIdx: number, strIdx: number, isNew: boolean, key: string, value: string) => { - if (!loc) return; - playPressSound(); - const newLoc = { ...loc }; - const lang = newLoc.languages[langIdx]; - if (isNew) { - lang.strings.push(lang.isStatic ? { value } : { key, value }); - } else { - if (!lang.isStatic) lang.strings[strIdx].key = key; - lang.strings[strIdx].value = value; - } - setLoc(newLoc); - setIsLocEditModalOpen(null); - showNotification(isNew ? t("arcEditor.stringAdded") : t("arcEditor.stringUpdated")); - }; - - const handleLocStringDelete = (langIdx: number, strIdx: number) => { - if (!loc) return; - playBackSound(); - const newLoc = { ...loc }; - newLoc.languages[langIdx].strings.splice(strIdx, 1); - setLoc(newLoc); - showNotification(t("arcEditor.stringDeleted")); - }; - - const treeData = useMemo(() => { - const root: Record = { name: "", children: {}, isFolder: true }; - filteredEntries.forEach((entry) => { - const parts = entry.filename.split(/\//); - let current = root; - parts.forEach((part, i) => { - const isLast = i === parts.length - 1; - if (!current.children[part]) { - current.children[part] = isLast - ? { ...entry, isFolder: false } - : { name: part, children: {}, isFolder: true }; - } - current = current.children[part]; - }); - }); - return root; - }, [filteredEntries]); - - const [expandedNodes, setExpandedNodes] = useState>(new Set([""])); - const toggleNode = (path: string) => { - const newExpanded = new Set(expandedNodes); - if (newExpanded.has(path)) newExpanded.delete(path); - else newExpanded.add(path); - setExpandedNodes(newExpanded); - }; - - const renderTree = (node: Record, path: string = "") => { - const nodePath = path ? `${path}/${node.name}` : node.name; - const isExpanded = expandedNodes.has(nodePath); - - if (!node.isFolder) { - const isSelected = selectedEntryIdx === node.originalIdx; - return ( -
{ playPressSound(); setSelectedEntryIdx(node.originalIdx); }} - className={`group flex items-center gap-2 px-2 py-1 cursor-pointer ${isSelected ? "bg-[#FFFF55]/20 text-[#FFFF55]" : "text-white/80"}`} - > - - - {node.filename.split("/").pop()} - - {node.isCompressed && ( - {t("arcEditor.zlib")} - )} -
- ); - } - - return ( -
-
{ playPressSound(); toggleNode(nodePath); }} - className="flex items-center gap-2 px-2 py-1.5 cursor-pointer text-white/50 group" - > - - ▶ - - - - {node.name} - -
- - {isExpanded && ( - - {Object.values(node.children as Record).map((child: Record) => renderTree(child, nodePath))} - - )} - -
- ); - }; - - const handleExportAll = async () => { - if (!arc || arc.entries.length === 0) return; - try { - const baseFolder = await TauriService.pickFolder(); - if (!baseFolder) return; - playPressSound(); - showNotification(t("arcEditor.exportingAll")); - - for (const entry of arc.entries) { - const fileName = entry.filename.replace(/\//g, "_"); - await TauriService.writeBinaryFile(`${baseFolder}/${fileName}`, entry.data); - } - showNotification(t("arcEditor.allEntriesExported")); - } catch (err: unknown) { - if (err !== "CANCELED") showNotification(t("arcEditor.exportFailed"), "error"); - } - }; - - const selectedEntry = selectedEntryIdx !== null ? arc?.entries[selectedEntryIdx] : null; - - return ( - -
-

- {t("arcEditor.title")} -

-
- - - -
-
- - - - - {!arc ? ( -
- -

{t("arcEditor.openArcFile")}

-
- ) : ( -
-
- - -
- -
- {activeTab === "arc" ? ( -
-
-
-
- setSearchTerm(e.target.value)} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - /> -
- -
-
- {renderTree(treeData)} -
-
-
- {selectedEntry ? ( -
-
-

{t("arcEditor.entryDetails")}

-

{selectedEntry.filename}

-
-
-
- {t("arcEditor.size")} - {(selectedEntry.size / 1024).toFixed(1)} KB -
-
- {t("arcEditor.format")} - {selectedEntry.isCompressed ? t("arcEditor.compressed") : t("arcEditor.raw")} -
-
- -
- - - - -
- -
-
-
- ) : ( -
- -

{t("arcEditor.selectEntry")}

-
- )} -
-
- ) : ( -
- {!loc ? ( -
-

{t("arcEditor.noLocFound")}

- -
- ) : ( -
-
- -
- setSearchTerm(e.target.value)} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - /> -
- - -
-
- - - - - - - - - - {filteredLocStrings.map((str) => ( - - - - - - ))} - -
{t("arcEditor.keyOrIndex")}{t("arcEditor.value")}{t("arcEditor.actions")}
- {currentLocLang?.isStatic ? str.originalIdx : str.key} - {str.value} -
- - -
-
-
-
- )} -
- )} -
-
- )} -
- -
- - {notification && ( - - - {notification.message} - - - )} - - {isAddModalOpen && ( -
-
-

{t("arcEditor.addFileToArchive")}

-
- -
- -
-
-
-
- )} - - {isReplaceModalOpen && selectedEntryIdx !== null && ( -
-
-

{t("arcEditor.replaceFileData")}

-

{arc?.entries[selectedEntryIdx].filename}

-
- -
- -
-
-
-
- )} - - {isRenameModalOpen && selectedEntryIdx !== null && ( - setIsRenameModalOpen(false)} - onConfirm={handleRenameEntry} - /> - )} - {isLocEditModalOpen && ( - setIsLocEditModalOpen(null)} - onConfirm={handleLocStringEdit} - /> - )} -
- ); -} - -function RenameModal({ initialName, initialCompressed, onClose, onConfirm }: { initialName: string, initialCompressed: boolean, onClose: () => void, onConfirm: (name: string, comp: boolean) => void }) { - const { t } = useTranslation(); - const [name, setName] = useState(initialName); - const [comp, setComp] = useState(initialCompressed); - return ( -
-
-

{t("arcEditor.renameEntry")}

-
-
- -
- setName(e.target.value)} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]" - /> -
-
- -
- - -
-
-
-
- ); -} - -function LocEditModal({ data, lang, onClose, onConfirm }: { data: { langIdx: number, strIdx: number, isNew: boolean }, lang: LocLanguage, onClose: () => void, onConfirm: (langIdx: number, strIdx: number, isNew: boolean, key: string, val: string) => void }) { - const { t } = useTranslation(); - const [key, setKey] = useState(!data.isNew ? (lang.strings[data.strIdx].key || "") : ""); - const [val, setVal] = useState(!data.isNew ? lang.strings[data.strIdx].value : ""); - return ( -
-
-

{data.isNew ? t("arcEditor.add") : t("arcEditor.edit")} {t("arcEditor.stringTitle")}

-
- {!lang.isStatic ? ( -
- -
- setKey(e.target.value)} - className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] font-mono" - /> -
-
- ) : ( -
{t("arcEditor.staticEntry", { index: data.isNew ? lang.strings.length : data.strIdx })}
- )} -
- -