From 63f918b7ee8076965d488a3565020b70eee6a472 Mon Sep 17 00:00:00 2001 From: knqiufan Date: Sat, 19 Sep 2026 20:09:44 +0800 Subject: [PATCH 01/31] feat(desktop): add S1 native foundation and Windows CI --- .github/workflows/desktop.yml | 59 + desktop/.gitattributes | 17 + desktop/.gitignore | 6 + desktop/.mise.toml | 17 + desktop/README.md | 54 + desktop/README.zh.md | 36 + desktop/SECURITY.md | 37 + desktop/evidence/S1.md | 116 + desktop/evidence/source-manifest.json | 52 + desktop/package.json | 49 + desktop/pnpm-lock.yaml | 2079 +++++ desktop/pnpm-workspace.yaml | 16 + desktop/rust-toolchain.toml | 18 + desktop/scripts/generate.mjs | 84 + desktop/scripts/icons.mjs | 57 + desktop/scripts/windows-smoke.ps1 | 65 + desktop/src-tauri/Cargo.lock | 5227 ++++++++++++ desktop/src-tauri/Cargo.toml | 50 + desktop/src-tauri/build.rs | 30 + desktop/src-tauri/capabilities/main.json | 11 + .../src-tauri/examples/credential_probe.rs | 52 + desktop/src-tauri/examples/export_ipc.rs | 50 + desktop/src-tauri/icons/brand.png | Bin 0 -> 4288 bytes desktop/src-tauri/icons/icon.ico | Bin 0 -> 28984 bytes desktop/src-tauri/icons/icon.png | Bin 0 -> 58520 bytes desktop/src-tauri/src/credentials.rs | 237 + desktop/src-tauri/src/error.rs | 40 + desktop/src-tauri/src/ipc.rs | 62 + desktop/src-tauri/src/lib.rs | 34 + desktop/src-tauri/src/main.rs | 20 + desktop/src-tauri/src/transport/mod.rs | 171 + .../src-tauri/src/transport/operations.json | 45 + desktop/src-tauri/tauri.conf.json | 59 + desktop/src-tauri/tests/ipc.rs | 84 + desktop/src-tauri/tests/tls.rs | 104 + desktop/src-tauri/tests/transport.rs | 264 + desktop/tsconfig.json | 27 + desktop/ui/index.html | 17 + desktop/ui/src/app/App.tsx | 272 + desktop/ui/src/app/messages.ts | 128 + desktop/ui/src/app/style.css | 398 + desktop/ui/src/assets/connections.svg | 1 + desktop/ui/src/assets/memory.svg | 1 + desktop/ui/src/assets/overview.svg | 1 + desktop/ui/src/generated/api.d.ts | 7553 +++++++++++++++++ desktop/ui/src/generated/ipc.ts | 22 + desktop/ui/src/generated/operations.ts | 60 + desktop/ui/src/main.tsx | 21 + desktop/ui/src/shared/ipc.ts | 22 + desktop/ui/tests/app.test.tsx | 55 + desktop/vite.config.ts | 26 + 51 files changed, 17906 insertions(+) create mode 100644 .github/workflows/desktop.yml create mode 100644 desktop/.gitattributes create mode 100644 desktop/.gitignore create mode 100644 desktop/.mise.toml create mode 100644 desktop/README.md create mode 100644 desktop/README.zh.md create mode 100644 desktop/SECURITY.md create mode 100644 desktop/evidence/S1.md create mode 100644 desktop/evidence/source-manifest.json create mode 100644 desktop/package.json create mode 100644 desktop/pnpm-lock.yaml create mode 100644 desktop/pnpm-workspace.yaml create mode 100644 desktop/rust-toolchain.toml create mode 100644 desktop/scripts/generate.mjs create mode 100644 desktop/scripts/icons.mjs create mode 100644 desktop/scripts/windows-smoke.ps1 create mode 100644 desktop/src-tauri/Cargo.lock create mode 100644 desktop/src-tauri/Cargo.toml create mode 100644 desktop/src-tauri/build.rs create mode 100644 desktop/src-tauri/capabilities/main.json create mode 100644 desktop/src-tauri/examples/credential_probe.rs create mode 100644 desktop/src-tauri/examples/export_ipc.rs create mode 100644 desktop/src-tauri/icons/brand.png create mode 100644 desktop/src-tauri/icons/icon.ico create mode 100644 desktop/src-tauri/icons/icon.png create mode 100644 desktop/src-tauri/src/credentials.rs create mode 100644 desktop/src-tauri/src/error.rs create mode 100644 desktop/src-tauri/src/ipc.rs create mode 100644 desktop/src-tauri/src/lib.rs create mode 100644 desktop/src-tauri/src/main.rs create mode 100644 desktop/src-tauri/src/transport/mod.rs create mode 100644 desktop/src-tauri/src/transport/operations.json create mode 100644 desktop/src-tauri/tauri.conf.json create mode 100644 desktop/src-tauri/tests/ipc.rs create mode 100644 desktop/src-tauri/tests/tls.rs create mode 100644 desktop/src-tauri/tests/transport.rs create mode 100644 desktop/tsconfig.json create mode 100644 desktop/ui/index.html create mode 100644 desktop/ui/src/app/App.tsx create mode 100644 desktop/ui/src/app/messages.ts create mode 100644 desktop/ui/src/app/style.css create mode 100644 desktop/ui/src/assets/connections.svg create mode 100644 desktop/ui/src/assets/memory.svg create mode 100644 desktop/ui/src/assets/overview.svg create mode 100644 desktop/ui/src/generated/api.d.ts create mode 100644 desktop/ui/src/generated/ipc.ts create mode 100644 desktop/ui/src/generated/operations.ts create mode 100644 desktop/ui/src/main.tsx create mode 100644 desktop/ui/src/shared/ipc.ts create mode 100644 desktop/ui/tests/app.test.tsx create mode 100644 desktop/vite.config.ts diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml new file mode 100644 index 000000000..f150276b2 --- /dev/null +++ b/.github/workflows/desktop.yml @@ -0,0 +1,59 @@ +name: Desktop foundation + +on: + pull_request: + paths: ['desktop/**', 'openapi/powercontext.yaml', 'tests/fixtures/transport_loopback_vectors.json', 'website/assets/**', '.github/workflows/desktop.yml'] + push: + branches: [master, codex/desktop-preview] + paths: ['desktop/**', 'openapi/powercontext.yaml', 'tests/fixtures/transport_loopback_vectors.json', 'website/assets/**', '.github/workflows/desktop.yml'] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: desktop-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + windows: + runs-on: windows-2025 + timeout-minutes: 40 + defaults: + run: + working-directory: desktop + shell: pwsh + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac # v2 + with: + working_directory: desktop + - name: Install pinned Windows Rust toolchain + run: rustup toolchain install 1.95.0-x86_64-pc-windows-msvc --profile minimal --component rustfmt --component clippy + - name: Install locked dependencies + run: pnpm install --frozen-lockfile + - run: pnpm lint + - run: pnpm typecheck + - run: pnpm test + - run: pnpm build + - run: cargo fmt --manifest-path src-tauri/Cargo.toml --check + - run: cargo clippy --locked --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings + - run: cargo test --locked --manifest-path src-tauri/Cargo.toml + - run: pnpm ipc:check + - name: Verify Windows vault across processes + run: cargo run --locked --manifest-path src-tauri/Cargo.toml --example credential_probe + - name: Build unsigned internal Windows installer + run: pnpm desktop:build + - name: Smoke test installed package + timeout-minutes: 5 + run: ./scripts/windows-smoke.ps1 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + if: always() + with: + name: desktop-windows-internal-unsigned + path: | + desktop/src-tauri/target/release/bundle/nsis/*-setup.exe + desktop/.artifacts/windows-smoke.json + if-no-files-found: error diff --git a/desktop/.gitattributes b/desktop/.gitattributes new file mode 100644 index 000000000..6a4b22287 --- /dev/null +++ b/desktop/.gitattributes @@ -0,0 +1,17 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +* text=auto eol=lf +*.png binary +*.ico binary diff --git a/desktop/.gitignore b/desktop/.gitignore new file mode 100644 index 000000000..5ec058bba --- /dev/null +++ b/desktop/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +src-tauri/target/ +src-tauri/gen/ +src-tauri/permissions/autogenerated/ +.artifacts/ diff --git a/desktop/.mise.toml b/desktop/.mise.toml new file mode 100644 index 000000000..34565706f --- /dev/null +++ b/desktop/.mise.toml @@ -0,0 +1,17 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +[tools] +node = "24.14.1" +pnpm = "11.13.1" diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 000000000..4c0f3a2d5 --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,54 @@ +# PowerContext Desktop — S1 foundation + +Internal Windows preview for [#1654](https://github.com/oceanbase/powercontext/issues/1654), following RFC #1455. It provides a packaged Tauri 2 shell with Home, Connections, My memories, Chinese/English settings, semantic light/dark/system themes and honest disconnected states. Connection management and Memory operations belong to S2/S3 and are not enabled here. + +See [中文说明](README.zh.md), [security boundary](SECURITY.md), and [qualification evidence](evidence/S1.md). This is not a supported or signed release, and does not close #1654 or #1428. + +## Build on Windows + +Use Windows 11 x64, Visual Studio C++ Build Tools with a Windows SDK, Node **24.14.1**, pnpm **11.13.1**, Rust **1.95.0 MSVC**, and WebView2. `desktop/.mise.toml`, `rust-toolchain.toml`, `pnpm-lock.yaml` and `src-tauri/Cargo.lock` pin the tools and dependencies independently of Python and the website. + +Some machines default to Rust's GNU host. In PowerShell, explicitly select the pinned MSVC host for this process: + +```powershell +rustup toolchain install 1.95.0-x86_64-pc-windows-msvc --profile minimal --component clippy --component rustfmt +$env:RUSTUP_TOOLCHAIN = '1.95.0-x86_64-pc-windows-msvc' +pnpm --dir desktop install --frozen-lockfile +pnpm --dir desktop desktop:dev +``` + +From the repository root: + +```powershell +pnpm --dir desktop lint +pnpm --dir desktop typecheck +pnpm --dir desktop test +pnpm --dir desktop build +pnpm --dir desktop ipc:check +cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check +cargo clippy --locked --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings +cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml +pnpm --dir desktop desktop:build +``` + +`build` produces UI assets only. `desktop:build` produces the release executable and current-user NSIS installer under `desktop/src-tauri/target/release/bundle/nsis/`. No Python, private HTTP server, or Vite process is embedded or started by the installed application. Closing the window exits Desktop. + +The unsigned installer is for internal verification. If WebView2 is absent, its configured download bootstrapper needs network access and may require the user to complete Microsoft installation prerequisites. The absent-runtime and standard-user cases require a disposable Windows environment; never remove a developer's WebView2 to simulate them. + +## Contracts and resources + +`pnpm --dir desktop generate` derives TypeScript schemas and the reviewed ten-operation manifest from `openapi/powercontext.yaml`; `generate:check` detects drift, including a normalized contract SHA-256. The Rust liveness adapter consumes that generated manifest. No public route is independently handwritten in the application. The manifest is not an IPC permission grant. + +`cargo run --locked --manifest-path desktop/src-tauri/Cargo.toml --example export_ipc` derives the TypeScript IPC request/receipt/error types from Rust. `ipc:check` verifies them. The only enabled IPC command is `foundation_info`; it returns safe build status, never secrets. The native-only vault/transport adapters are S2 inputs, not a connection UI. + +The canonical brand source is `website/assets/powercontext-color.png`, which is read directly without running the website. `pnpm --dir desktop icons` extracts its square mark and uses the pinned Tauri CLI to derive the Windows icon; `icons:check` verifies all three generated assets against the canonical source. UI SVGs originate from the repository's Desktop design assets and are promoted into `ui/src/assets/` for reproducible builds. They are project resources under the repository Apache-2.0 license. + +## Native credential feasibility + +```powershell +cargo run --locked --manifest-path desktop/src-tauri/Cargo.toml --example credential_probe +``` + +This explicit probe creates a uniquely named synthetic credential in the preview namespace, loads it in another process and deletes it. It never reads another application's credential or prints a secret. Normal tests simulate unavailable storage and require an explicit session-only choice. Do not treat the probe as end-to-end S2 credential-form verification. + +The Windows CI workflow runs on PRs and the preview branch, verifies native vault persistence, builds an unsigned internal installer, and tests Chinese-path installation/uninstallation on its disposable runner. It uploads the installer and a JSON smoke report. CI and mocked IPC tests do not prove clean-machine installation, notification activation, independent service login or Agent capture/recall. diff --git a/desktop/README.zh.md b/desktop/README.zh.md new file mode 100644 index 000000000..7d37192c0 --- /dev/null +++ b/desktop/README.zh.md @@ -0,0 +1,36 @@ +# PowerContext Desktop:S1 工程基础 + +这是 #1654 的内部工程预览。已建立 Tauri 2、React、TypeScript 和 Vite 独立工程,提供首页、连接、我的记忆、双语设置及浅色/深色/系统主题。无连接时保存和搜索不可用,不展示示例业务数据。 + +连接配置与身份验证属于 S2,Memory 保存、搜索和精确阅读属于 S3。当前不是完整连接预览,也不是已签名的正式 Windows 发行版。 + +## 开发与构建 + +Windows 11 x64 上需要 Node 24.14.1、pnpm 11.13.1、Rust 1.95.0 MSVC、Visual Studio C++ Build Tools、Windows SDK 和 WebView2。安装后的用户程序不依赖 Node、Rust、Python 或本地 Server。 + +从仓库根目录执行: + +```powershell +rustup toolchain install 1.95.0-x86_64-pc-windows-msvc --profile minimal --component clippy --component rustfmt +$env:RUSTUP_TOOLCHAIN = '1.95.0-x86_64-pc-windows-msvc' +pnpm --dir desktop install --frozen-lockfile +pnpm --dir desktop desktop:dev +``` + +`pnpm --dir desktop build` 只构建前端。`pnpm --dir desktop desktop:build` 构建原生 release 程序和当前用户 NSIS 安装包,输出到 `desktop/src-tauri/target/release/bundle/nsis/`。完整检查入口见 [英文 README](README.md)。 + +缺少 WebView2 时,安装器配置为下载 Microsoft bootstrapper,需要网络。标准用户、无 WebView2、无 Python 的干净机器场景必须在隔离环境验证,不能通过卸载开发机依赖来模拟。 + +## S2 可用输入 + +- OpenAPI 自动派生的 TypeScript schema 和十项 operation 映射,包含契约摘要及漂移检查。 +- Rust 自动派生的 IPC 类型与安全错误;凭据只写请求必须显式选择持久化或仅会话,成功回执只含存储模式,不含秘密或凭据标识。 +- Windows Credential Manager 原生适配器;保存失败直接报错,只有显式选择才采用仅会话内存。秘密类型不支持序列化,不实现 Debug。 +- 使用系统证书信任的原生 HTTPS;可为单个客户端添加显式 CA,继续校验主机名。 +- HTTP 仅允许 loopback,拒绝地址中的用户信息、查询、片段、反斜杠及路径逃逸;不继承代理、不跟随重定向。 +- 连接超时 5 秒、完整请求超时 15 秒、响应上限 1 MiB、每个客户端最多 4 个并发读取;超限明确失败。 +- 唯一启用的 IPC 是只读 `foundation_info`。凭据和传输适配器只在 Rust 中使用,没有通用 fetch、shell、文件、数据库或读取秘密的 IPC。 + +应用不启动 Server、不管理服务、不持久化正文或查询;关闭窗口即退出。当前语言和主题也仅保留于会话内。 + +[安全边界](SECURITY.md)记录具体约束;[S1 验证记录](evidence/S1.md)区分已经执行的测试和仍未满足的 P0 门槛。构建成功、Mock 测试和当前用户机器上的运行都不能代替标准用户、签名、通知冷启动激活、独立服务和 Agent 宿主验收。 diff --git a/desktop/SECURITY.md b/desktop/SECURITY.md new file mode 100644 index 000000000..5b7927443 --- /dev/null +++ b/desktop/SECURITY.md @@ -0,0 +1,37 @@ +# Native boundary + +## Renderer + +Only the packaged main window receives the explicit `main` capability. The app manifest enumerates `foundation_info`, so Tauri does not implicitly grant custom commands to every window. The handler also checks the native window label. No capability grants a remote origin, general HTTP, shell, filesystem, SQL, notification, opener or credential-read access. + +Production CSP allows packaged scripts/styles/images and Tauri IPC only, with no remote frames, forms or network fetch. The navigation callback permits the packaged origin, and permits the exact Vite origin only in debug builds. Production builds use Tauri's `custom-protocol` feature. No CSP bypass, unsafe eval, remote image or HTML execution is enabled. React renders text, never `dangerouslySetInnerHTML`. + +## Secrets and transport + +The vault namespace is `com.powercontext.desktop.preview`. A native credential ID is an opaque bounded identifier; it is not an endpoint or a user-controlled vault path. Windows credentials use the OS store only. Unavailable storage returns a stable error; session-only storage is an explicit separate choice. Secret values have zeroizing storage and cannot be serialized or debug formatted. The renderer has no secret readback operation. The synthetic opt-in probe only touches its unique test entry. + +The Rust-derived write protocol accepts only `secret` and an explicit `storage` choice (`persistent` or `session_only`). Its input cannot be serialized; the success receipt contains only the storage choice. Missing modes, unknown modes and extra fields are rejected. The native caller supplies the credential ID; the renderer cannot choose a vault address. A failed persistent write produces no success receipt or automatic fallback. + +S2 must create IDs in native code, bind credentials to an exact endpoint/trust configuration, invalidate them on changes, and add a write-only credential command only with the corresponding context and capability checks. S1 does not expose an incomplete credential form or persist connection profiles. + +Native reqwest uses Windows system trust through native-tls/Schannel, plus an optional connection-local PEM CA (maximum 64 KiB). Hostname/certificate validation remains enabled. Automatic proxy inheritance and redirects are disabled. HTTP requires loopback. Userinfo, query, fragment, control characters, backslashes and dot segments are rejected before URL normalization. Percent-encoded base paths are conservatively rejected in S1; literal UTF-8 path prefixes are accepted. Public operation paths come from the generated OpenAPI manifest and preserve the base prefix. + +Only the liveness read is implemented in S1. It verifies the response's `status: ok` without inferring authentication, compatibility or readiness. No business write or retry queue exists. S2 must implement typed operation-specific adapters, scope/context generation checks and ambiguous-write recovery before exposing business operations. + +## Budgets and error projection + +| Boundary | Limit | +| --- | --- | +| Endpoint input | 2048 bytes | +| Bearer input | 1–2048 printable ASCII bytes | +| Additional CA PEM | 64 KiB | +| Connect timeout | 5 seconds | +| Complete request, including response body | 15 seconds | +| Response body | 1 MiB, checked both by declared size and streamed bytes | +| Concurrent liveness reads per client | 4; excess fails as busy | + +Error responses are enum codes. Transport exception text, endpoint URLs, bodies and credentials are never returned or logged. No product logging, telemetry, crash uploader or persistent business cache is configured. The app does not read databases, start a Server, inspect process environments or run CLI diagnostics. + +Tests cover actual TLS fixtures and adversarial HTTP responses, shared loopback policy, mocked Tauri permission resolution with the real capability configuration, navigation rejection, unavailable vault behavior and the explicit session path. The opt-in Windows vault probe separately verifies persistence across processes. Packaged native and isolated machine results are tracked in [the evidence record](evidence/S1.md). + +Framework references: [Tauri capabilities](https://v2.tauri.app/security/capabilities/), [Windows installer options](https://v2.tauri.app/distribute/windows-installer/). diff --git a/desktop/evidence/S1.md b/desktop/evidence/S1.md new file mode 100644 index 000000000..6a1a57904 --- /dev/null +++ b/desktop/evidence/S1.md @@ -0,0 +1,116 @@ +# S1 foundation evidence — 2026-09-19 + +## Conclusion + +The S1 foundation is implemented and has developer-machine native smoke evidence. S1-08 and S1-09 are not complete. **S1 exit qualification and official P0 remain blocked.** There is no accepted Server compatibility profile and no claim of complete #1654 delivery. + +Implementation branch: `codex/desktop-preview`, based on upstream `aa697c5315204249e090acdf1a00d0582e851c5f` (fetched at task start). [source-manifest.json](source-manifest.json) identifies the source files used for this evidence. No backend or OpenAPI contract changes were made. + +## Remote CI scope + +The Windows workflow runs on pull requests and pushes to `codex/desktop-preview`. It uses locked dependencies, checks the UI and Rust code, verifies generated contracts, exercises the Windows vault across processes, builds the unsigned installer, and installs/uninstalls it in a Chinese path on the disposable runner. It uploads the installer and a JSON report containing package digest, signature status and lifecycle results. CI results must be read from the corresponding commit's Actions run; workflow configuration alone is not passing evidence. + +Hosted runners are developer images with preinstalled software and do not prove a clean standard-user desktop, absent WebView2, interactive rendering, notification activation or host integration. The external sentinel check proves only preservation of that synthetic file, not a real Server database. Those gates remain open independently of the draft PR. + +## Requirement coverage + +| Requirement | Evidence and remaining work | +| --- | --- | +| S1-01 | Independent worktree/branch and exact baseline recorded below; backend untouched. | +| S1-02 | Independent locks, build/CI entry points and real NSIS build; Python wheel and website regression passed. | +| S1-03 | Three-page native shell, bilingual resources/themes; installed keyboard and zoom observations below. Complete accessibility qualification remains open. | +| S1-04 | OpenAPI-generated operation manifest and schemas; Rust-derived IPC types; drift checks passed. | +| S1-05 | Explicit manifest/capability/CSP and navigation guard; native permission-resolution tests reject untrusted callers and unregistered commands. | +| S1-06 | Real Windows vault persistence across processes plus cleanup; explicit session and unavailable-vault tests. Write-only request/receipt protocol is generated from Rust and tested; live connection command belongs to S2. | +| S1-07 | Real HTTP/TLS fixtures cover loopback, base prefix, system/custom trust, hostname, proxy and authenticated redirect policy. | +| S1-08 | Internal unsigned installer and developer-machine Chinese-path smoke evidence only. Clean standard user, absent WebView2 and absent Python/Server are blocked. | +| S1-09 | Not executed: notification cold-start, independent service/login and selected Agent host require the isolated P0 environment and named responsible parties. | + +No row marked blocked is counted as completed. Existing developer-machine evidence cannot establish standard-user or complete P0 qualification. + +## Environment and package + +| Field | Observed value | +| --- | --- | +| Operator | Codex-assisted execution in the user's developer environment; no independent reviewer | +| OS | Windows 11 Pro x64, 10.0.26200 | +| CPU | AMD Ryzen 9 8945HX | +| Account | Existing developer administrator account; not a clean standard-user qualification | +| WebView2 | 153.0.4234.32, already installed | +| Node / pnpm | 24.14.1 / 11.13.1 | +| Rust | 1.95.0 (59807616e), x86_64-pc-windows-msvc | +| Toolchain | Visual Studio Build Tools, MSVC 14.44.35207 | +| Tauri / React / TypeScript / Vite | 2.11.0 / 19.2.8 / 5.9.3 / 8.3.0; exact transitives in lockfiles | +| Build | Release, packaged assets via custom-protocol, NSIS current-user installer | +| Installer | PowerContext Desktop Preview_0.1.0_x64-setup.exe | +| Installer size | 1,920,485 bytes | +| Installer SHA-256 | 9F29FF7ACDD706FB0A7B84A2BBFFBC673ECF2E705C3FE6E1318C178874FD8395 | +| Authenticode | NotSigned | +| Contract SHA-256 (LF normalized) | de9750808e12e7a6c7a88b736b5368ba3b7c5fcf3c986f1c8cb762b66afce03c | +| Server / Provider / Agent compatibility | None qualified in S1 | + +The installer is a local, ignored build artifact under `src-tauri/target/release/bundle/nsis/`, not a published release. The app namespace is isolated as `com.powercontext.desktop.preview`. + +## Automated validation + +| Command / check | Result | +| --- | --- | +| `pnpm --dir desktop install --frozen-lockfile` | Passed | +| `pnpm --dir desktop lint` | Passed: lint, OpenAPI drift, canonical brand drift, formatting | +| `pnpm --dir desktop typecheck` | Passed | +| `pnpm --dir desktop test` | 2 UI behavior tests passed | +| `pnpm --dir desktop build` | Passed; independently bundled UI | +| `pnpm --dir desktop ipc:check` | Passed; Rust-derived IPC types match | +| `cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check` | Passed | +| `cargo clippy --locked --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings` | Passed | +| `cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml` | 14 behavior tests passed (2 vault/protocol, 2 IPC/navigation, 1 TLS, 9 transport) | +| `cargo run --locked --manifest-path desktop/src-tauri/Cargo.toml --example credential_probe` | Passed against the real Windows vault | +| `pnpm --dir desktop desktop:build` | Passed; NSIS installer created | +| `uv lock --locked` | Passed | +| Workflow immutable-action check | Passed, including the Desktop workflow | +| Integration manifest generation check | Passed | +| `uv run python -m pytest tests/test_integration_manifest.py tests/test_transport.py -q` | 85 passed | +| `uv build --wheel` and wheel file inspection | Passed; wheel contains no Desktop sources | +| Repository pre-commit checks | Formatting/lint checks passed after fixes; ty remains blocked by the seven existing Windows errors below | +| Pydantic AI integration ty check | Passed | +| Website lint/tests/build (underlying docs-test commands) | Passed; 820 public pages and their internal links verified | + +This host has no `make` executable. The underlying lock, workflow, integration-manifest, pre-commit and ty commands from `make check` were run directly. The seven existing Windows type errors are five PipeConnection/Connection mismatches and two POSIX WNOHANG references, matching the boundary tracked in #1658. Three additional deprecation warnings are not new Desktop failures. No backend ignores or patches were added. + +The native tests use actual loopback HTTP/TLS listeners: proxy-prefix preservation, auth header placement, 401/403/5xx safe projection, redirect target not contacted, known-length and chunked overflow, stalled-body total timeout, poisoned proxy environment, concurrent-read saturation/cancellation recovery, explicit CA trust, untrusted CA and hostname mismatch. IPC tests exercise Tauri's real manifest/capability resolution using its mock runtime, including an unauthorized window, remote origin, shell, fetch and secret-read attempts. They are not a substitute for an installed-package penetration test. + +## Native observations + +These installed-package observations apply to the 1,931,703-byte installer with SHA-256 `E50612678944E8BBA0AED5A712A516BDEDA659B619F55E8D43927C58E256F1A1`. The current package listed above was rebuilt successfully after the native-only write-protocol addition; its installed UI smoke has not been repeated. No renderer behavior, command registration, capability or installer configuration changed. + +1. Ran the unsigned NSIS installer with `/S` and a dedicated installation directory containing `安装验证`. It returned exit code 0. The installation contained the application and uninstaller, with no exporter/helper, Python or Server binary. +2. Launched the installed executable with a process-specific PATH containing only Windows System32. No Vite server or local PowerContext Server was started. The packaged homepage rendered; save/search were disabled and no sample business data was shown. +3. Windows UI Automation and window capture observed `http://tauri.localhost/`, version 0.1.0 and native-host status Ready. Switched to English and Dark using native UI and keyboard input; labels and semantic colors changed. +4. Exercised five zoom-in shortcuts from the default zoom. At approximately 200%, the navigation collapsed into a menu; it could be opened and used to reach Connections. Text flowed vertically without a fixed-height three-panel layout. Exact 800×600, screen-reader, high-contrast and complete keyboard/IME qualification remain outstanding. +5. Closed the window using Alt+F4 and verified the application process exited. Its observed process tree consisted of Desktop and WebView2 only; no Python or Server child appeared. +6. Ran the dedicated uninstaller with `/S`; exit code 0. The application executable was removed. A synthetic external data sentinel outside the installation directory remained byte-for-byte unchanged. This is not evidence for an actual Server service/database lifecycle. +7. The credential probe wrote a unique synthetic entry, launched a separate process that read it, removed it and verified it was absent. No secret was printed or returned to the renderer. The write-protocol test rejects missing/unknown storage choices and renderer-supplied IDs, checks safe invalid-secret errors, and verifies that the entire successful response contains only storage metadata. Unit tests separately showed that vault failure does not become session storage without an explicit session-only choice. + +Local machine-readable smoke observations are retained under ignored `desktop/.artifacts/`. Window observations are in the current Codex task's computer-use tool record. + +## Measurements and limits + +One process-launch sample reached a native window handle in **530 ms**; this is not time-to-interactive or a p50/p95 cold-start baseline. A later seven-process Desktop/WebView2 sample used 524,025,856 bytes summed working set and 241,205,248 bytes summed private memory. Its ten-second interval included UI automation and recorded 2.5 CPU seconds, so it **must not be reported as idle CPU**. Shared working sets may be double counted. + +No Server was included. No wakeup rate, search latency, data scale or statistically meaningful performance budget was measured. Full-product performance qualification remains open. + +## Outstanding gates and S2 handoff + +| Gate | Status / unblock condition | +| --- | --- | +| Clean Windows standard user; Python/Server absent | Blocked: disposable target environment needed. Restricted PATH is only a developer smoke test. | +| WebView2 absent, bootstrap/offline/error recovery | Blocked: disposable VM needed; existing developer runtime was not removed. | +| Signed package and release identity | Blocked: signing certificate and named Release responsibility not supplied. | +| Notification permission / installed cold-start activation | Not executed: isolated P0 experiment and responsible owner needed; no business notification feature added. | +| Independent service, login/reboot behavior | Not executed: isolated service environment and Server/Install owner needed. | +| Exact Agent host and real capture/recall | Not executed: qualified host/version and dedicated Server fixture needed. | +| Desktop / Server / Install / Release named ownership | Pending user/maintainer coordination; no commitments inferred. | +| Full performance and accessibility qualification | Not executed; developer observations above are partial. | +| Windows backend qualification (#1658) | Existing errors reproduced; follow the independent upstream fix. | + +S2 can consume the native vault, safe error types, transport budgets, generated API manifest and UI shell. It must wire the existing credential write-only request/receipt protocol into a context-checked IPC handler, native-owned connection IDs/generation, endpoint/trust-bound secret invalidation, compatibility evidence, identity/readiness and scope handling before enabling business actions. No Server baseline is automatically trusted. diff --git a/desktop/evidence/source-manifest.json b/desktop/evidence/source-manifest.json new file mode 100644 index 000000000..3ef8bb221 --- /dev/null +++ b/desktop/evidence/source-manifest.json @@ -0,0 +1,52 @@ +{ + "algorithm": "SHA-256", + "baseCommit": "aa697c5315204249e090acdf1a00d0582e851c5f", + "files": { + "desktop/.gitattributes": "e861d974e31c847b35f5a17ba0c442c00b5e6204a9fd22475aee367db57802ca", + "desktop/.gitignore": "d9dc197ff5a68fa87d4b803a2548de630f0d2f5162f9bc228782a998a8fe91bd", + "desktop/.mise.toml": "dbf0eb56655bde88f4f7c1aa3781fe26de6e49e06be50fcf97db4bda5c1e26db", + "desktop/package.json": "4735d9fc9d1f77c7dd18ab9c67bf2a2fc73dbda8dcd19a6270926894efa49a3e", + "desktop/pnpm-lock.yaml": "d1ecf3e76c569cd19d2e8121e4dc9f0420fa30f48faaa791b66396d5efed730e", + "desktop/pnpm-workspace.yaml": "5946bc4237b6ff484037870fbbe508cf053a9beccd3f2d0567858adf23a9c8be", + "desktop/rust-toolchain.toml": "050bd535fc1ff64b1c2e01651f00f4937bcd559fc787679f1157aafe178af05e", + "desktop/scripts/generate.mjs": "918893d09900d147f45a6e2d8785299adfac7cd8f11cc837ebd8b28eef9cfbf7", + "desktop/scripts/icons.mjs": "596d53761a804425ccf285a9e897442434745f2438baae86d702fc7e38e988b3", + "desktop/src-tauri/build.rs": "676f0ad813c595bdc9fae6de27df65e0779a2853c3ce87c1fdfea40e001039ff", + "desktop/src-tauri/capabilities/main.json": "6eb2b89504d8c58bc127abfca44ddaa5d46b7864032c440a34f961cff44147aa", + "desktop/src-tauri/Cargo.lock": "6045e2fcc843792f7dc678cef4e2fa07a2ed97e80191b4ca0755e048e74b0c7d", + "desktop/src-tauri/Cargo.toml": "7513f5f4c78f6ca5c9792e96d6e47eba14f8495214f587b4a4e11825ba8f74da", + "desktop/src-tauri/examples/credential_probe.rs": "d57ee47bb15b53d969d9543370587bc010f626ea6da793b86c6c018c33552737", + "desktop/src-tauri/examples/export_ipc.rs": "91726d6cf36d52ee048b4535ebc28ad9dd47285c476b22621bb31bbf06987f54", + "desktop/src-tauri/icons/brand.png": "6290e31c3cc920f827d52bded3db56a012ed6aba239bb423771c8c769e24b794", + "desktop/src-tauri/icons/icon.ico": "2739d373ed7ce348f7c00b2dc6dc66331e0ebd151d4deb92de81c0bc8435cae2", + "desktop/src-tauri/icons/icon.png": "d9621cfb49788516d6113f2e822bc03de739d486865ce9680becfca76568902b", + "desktop/src-tauri/src/credentials.rs": "63d13ac95fafac2e8b25320165319a5bf8c9a2ceb8521ee5f63d759583047fe9", + "desktop/src-tauri/src/error.rs": "a3bd62f84df513da6bbedead573a831bf5ac91619043169670d230c91eec2859", + "desktop/src-tauri/src/ipc.rs": "db330929b2303672f4f12cdc0a6ba4bd3a8de0adc45f321600823043fe373e87", + "desktop/src-tauri/src/lib.rs": "f9d3ab770dea3cbf2bc0db4bdd2194641c832b49852df624b77c0583b25581d1", + "desktop/src-tauri/src/main.rs": "3e78ad1e12cf02524caefeaca0a8e1d355ccb167025ccd4b90a66eac0f9974f7", + "desktop/src-tauri/src/transport/mod.rs": "77c1e4973ded396f1fefc3dd26f0fa960d49a6091e19d646ea08e544fa58ff1f", + "desktop/src-tauri/src/transport/operations.json": "e336d58bae6319b9c90e11e0b11c22c47f60650483f5b9d8d396ceb627333973", + "desktop/src-tauri/tauri.conf.json": "a9c94ac973c658cfa16f1fa8613dd21f9267934357367332ed6fa98ff223fdd1", + "desktop/src-tauri/tests/ipc.rs": "a9221a8ea2e35069a1fad96a74a6e158e9ffcb5cad0f16071971ff0a2c6c98c5", + "desktop/src-tauri/tests/tls.rs": "c1d33986368b732d772759a91393d68821200f423f7db3a5e738e0bae5f90fd2", + "desktop/src-tauri/tests/transport.rs": "5f5965543062516397dc63419abe7073669e98c9c4cb6648428629fed904922b", + "desktop/tsconfig.json": "d675aa0fb23f549589c5f61209d29bc08451f6e222c56b7e25d1755252ccf2ff", + "desktop/ui/index.html": "821dda39212fb3f18c07829a65ec6da20f559e969eb4dc6276cacce4ccbff511", + "desktop/ui/src/app/App.tsx": "c1bb096637e4f2a139b7a90336b1bbb3056e142422e9e07f214f02f4bb0970d3", + "desktop/ui/src/app/messages.ts": "883ef94575f36d5ef6d71b16c7461256657ceb474511f5914d2261cf8a31e82f", + "desktop/ui/src/app/style.css": "3c3a4e7a44cc12ab8b9a1abf904c00b8ae43a186d3e43a91ce6d1f964ffd3223", + "desktop/ui/src/assets/connections.svg": "e15016461cfcfcbf173f6dd36b4a2dd528c4ca3e1a0a9e7f35f3bfb8462ad898", + "desktop/ui/src/assets/memory.svg": "10d6038ffdd02bb0ec97725ec8fe0a0eaa5535c1a7a0baa03af5bc8663f44f01", + "desktop/ui/src/assets/overview.svg": "532e26726d8223f301a5fb996f75fd38e80a4e143642300615254e86023240ad", + "desktop/ui/src/generated/api.d.ts": "0ab11a453eaf86ab63c7c35f624cfe5d5e6b60a2cce8aa0890e4c263cbdc2ee2", + "desktop/ui/src/generated/ipc.ts": "25192168a9caa50666ae9ae743a4f3d1fb872711c12ba10f9a20d44a90864233", + "desktop/ui/src/generated/operations.ts": "5683b2f3b6329e3e184cc06b6b4eca52dc4d275342ce4d9c50cc3c76e5a7f0b5", + "desktop/ui/src/main.tsx": "ef2cde0a9a5c7a9bea5c37f05d4a7e111fadeba6519c4813b55b5059f1d77d66", + "desktop/ui/src/shared/ipc.ts": "35585044901f502b0aa649ab34aed4437c3c82620eb2425925bf348f0c1f88b0", + "desktop/ui/tests/app.test.tsx": "5da31c5bef77f4e59771d84cd7e31f56b5846da38d483ba7098df1d33f93fdee", + "desktop/vite.config.ts": "a90de8f19b1b2f01fe801f0797630ec5b44874d1cd05da7360244ac136f12624", + ".github/workflows/desktop.yml": "adbe6433d6a2ffbe442abd55cdeeb1b32ab5ea2f3d399cf42d26439bfe41b675", + "desktop/scripts/windows-smoke.ps1": "b36588f165a53b6ab5fefab340da5e089dc125015e874427d4fe61653b08cd2d" + } +} diff --git a/desktop/package.json b/desktop/package.json new file mode 100644 index 000000000..ca025974c --- /dev/null +++ b/desktop/package.json @@ -0,0 +1,49 @@ +{ + "name": "powercontext-desktop", + "version": "0.1.0", + "private": true, + "type": "module", + "packageManager": "pnpm@11.13.1", + "engines": { + "node": "24.14.1" + }, + "scripts": { + "dev": "vite --host 127.0.0.1", + "generate": "node scripts/generate.mjs", + "generate:check": "node scripts/generate.mjs --check", + "lint": "oxlint ui scripts && pnpm generate:check && pnpm icons:check && pnpm format:check", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "pnpm generate:check && tsc --noEmit && vite build", + "tauri": "tauri", + "desktop:dev": "tauri dev", + "desktop:build": "tauri build --bundles nsis --ci -- --locked", + "ipc:check": "cargo run --locked --manifest-path src-tauri/Cargo.toml --example export_ipc -- --check", + "format:check": "prettier --check ui/src/app ui/src/shared ui/tests scripts vite.config.ts", + "icons": "node scripts/icons.mjs", + "icons:check": "node scripts/icons.mjs --check" + }, + "dependencies": { + "@tauri-apps/api": "2.11.1", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@tauri-apps/cli": "2.11.4", + "@testing-library/react": "16.3.0", + "@testing-library/user-event": "14.6.1", + "@types/node": "26.3.0", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.5", + "@vitejs/plugin-react": "6.1.1", + "jsdom": "26.1.0", + "openapi-typescript": "7.13.0", + "oxlint": "1.80.0", + "prettier": "3.6.2", + "sharp": "0.34.5", + "typescript": "5.9.3", + "vite": "8.3.0", + "vitest": "5.0.1", + "yaml": "2.9.0" + } +} diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml new file mode 100644 index 000000000..303b5ced5 --- /dev/null +++ b/desktop/pnpm-lock.yaml @@ -0,0 +1,2079 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@tauri-apps/api': + specifier: 2.11.1 + version: 2.11.1 + react: + specifier: 19.2.8 + version: 19.2.8 + react-dom: + specifier: 19.2.8 + version: 19.2.8(react@19.2.8) + devDependencies: + '@tauri-apps/cli': + specifier: 2.11.4 + version: 2.11.4 + '@testing-library/react': + specifier: 16.3.0 + version: 16.3.0(@testing-library/dom@10.4.2)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@testing-library/user-event': + specifier: 14.6.1 + version: 14.6.1(@testing-library/dom@10.4.2) + '@types/node': + specifier: 26.3.0 + version: 26.3.0 + '@types/react': + specifier: 19.2.18 + version: 19.2.18 + '@types/react-dom': + specifier: 19.2.5 + version: 19.2.5(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: 6.1.1 + version: 6.1.1(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0)) + jsdom: + specifier: 26.1.0 + version: 26.1.0(supports-color@10.2.2) + openapi-typescript: + specifier: 7.13.0 + version: 7.13.0(typescript@5.9.3) + oxlint: + specifier: 1.80.0 + version: 1.80.0 + prettier: + specifier: 3.6.2 + version: 3.6.2 + sharp: + specifier: 0.34.5 + version: 0.34.5 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: 8.3.0 + version: 8.3.0(@types/node@26.3.0)(yaml@2.9.0) + vitest: + specifier: 5.0.1 + version: 5.0.1(@types/node@26.3.0)(jsdom@26.1.0(supports-color@10.2.2))(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0)) + yaml: + specifier: 2.9.0 + version: 2.9.0 + +packages: + + '@asamuzakjp/css-color@3.2.0': + resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@oxc-project/types@0.150.0': + resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} + + '@oxlint/binding-android-arm-eabi@1.80.0': + resolution: {integrity: sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxlint/binding-android-arm64@1.80.0': + resolution: {integrity: sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxlint/binding-darwin-arm64@1.80.0': + resolution: {integrity: sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxlint/binding-darwin-x64@1.80.0': + resolution: {integrity: sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxlint/binding-freebsd-x64@1.80.0': + resolution: {integrity: sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': + resolution: {integrity: sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm-musleabihf@1.80.0': + resolution: {integrity: sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm64-gnu@1.80.0': + resolution: {integrity: sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-arm64-musl@1.80.0': + resolution: {integrity: sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-ppc64-gnu@1.80.0': + resolution: {integrity: sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-gnu@1.80.0': + resolution: {integrity: sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-musl@1.80.0': + resolution: {integrity: sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-s390x-gnu@1.80.0': + resolution: {integrity: sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-gnu@1.80.0': + resolution: {integrity: sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-musl@1.80.0': + resolution: {integrity: sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxlint/binding-openharmony-arm64@1.80.0': + resolution: {integrity: sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxlint/binding-win32-arm64-msvc@1.80.0': + resolution: {integrity: sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxlint/binding-win32-ia32-msvc@1.80.0': + resolution: {integrity: sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxlint/binding-win32-x64-msvc@1.80.0': + resolution: {integrity: sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} + + '@redocly/openapi-core@1.34.20': + resolution: {integrity: sha512-ypeBZ/6BKXR9+7/TtbKhbl4UgD7raHhPS12oknlKno2A8+lnFkxIwiE/Aklu6L2cd/ioH+fCWuMxi9/p3EyAPw==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + + '@rolldown/binding-android-arm-eabi@1.2.9': + resolution: {integrity: sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.9': + resolution: {integrity: sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.9': + resolution: {integrity: sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.9': + resolution: {integrity: sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.9': + resolution: {integrity: sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.9': + resolution: {integrity: sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.9': + resolution: {integrity: sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.9': + resolution: {integrity: sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.9': + resolution: {integrity: sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.9': + resolution: {integrity: sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.9': + resolution: {integrity: sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.9': + resolution: {integrity: sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.9': + resolution: {integrity: sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.9': + resolution: {integrity: sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.9': + resolution: {integrity: sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tauri-apps/api@2.11.1': + resolution: {integrity: sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==} + + '@tauri-apps/cli-darwin-arm64@2.11.4': + resolution: {integrity: sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tauri-apps/cli-darwin-x64@2.11.4': + resolution: {integrity: sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': + resolution: {integrity: sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': + resolution: {integrity: sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tauri-apps/cli-linux-arm64-musl@2.11.4': + resolution: {integrity: sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': + resolution: {integrity: sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@tauri-apps/cli-linux-x64-gnu@2.11.4': + resolution: {integrity: sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tauri-apps/cli-linux-x64-musl@2.11.4': + resolution: {integrity: sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': + resolution: {integrity: sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': + resolution: {integrity: sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@tauri-apps/cli-win32-x64-msvc@2.11.4': + resolution: {integrity: sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tauri-apps/cli@2.11.4': + resolution: {integrity: sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==} + engines: {node: '>= 10'} + hasBin: true + + '@testing-library/dom@10.4.2': + resolution: {integrity: sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==} + engines: {node: '>=18'} + + '@testing-library/react@16.3.0': + resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/node@26.3.0': + resolution: {integrity: sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==} + + '@types/react-dom@19.2.5': + resolution: {integrity: sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + + '@vitejs/plugin-react@6.1.1': + resolution: {integrity: sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + oxc-transform-react: ^0.145.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + oxc-transform-react: + optional: true + + '@vitest/mocker@5.0.1': + resolution: {integrity: sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/spy@5.0.1': + resolution: {integrity: sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@2.1.7: + resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + + cssstyle@4.6.0: + resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} + engines: {node: '>=18'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + 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'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + 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] + + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + jsdom@26.1.0: + resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@1.4.1: + resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.19: + resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nwsapi@2.2.27: + resolution: {integrity: sha512-gQPNF78qebCQ6tvVFBYrvJdBNOrYZm90ZlXgpIFm06p6qHDHq/XC4TnJftN6OMbxVE0UTBAoRgcsDeJBBooITw==} + + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} + + openapi-typescript@7.13.0: + resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + + oxlint@1.80.0: + resolution: {integrity: sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=7.0.2001' + vite-plus: '*' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + vite-plus: + optional: true + + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} + peerDependencies: + react: ^19.2.8 + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + rolldown@1.2.9: + resolution: {integrity: sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tinybench@6.1.4: + resolution: {integrity: sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==} + engines: {node: '>=20.0.0'} + + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + hasBin: true + + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + + vite@8.3.0: + resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.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 + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@5.0.1: + resolution: {integrity: sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.1 + '@vitest/browser-preview': 5.0.1 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.1 + '@vitest/coverage-v8': 5.0.1 + '@vitest/ui': 5.0.1 + happy-dom: '*' + jsdom: '*' + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + +snapshots: + + '@asamuzakjp/css-color@3.2.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/runtime@7.29.7': {} + + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-tokenizer@3.0.4': {} + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@oxc-project/types@0.150.0': {} + + '@oxlint/binding-android-arm-eabi@1.80.0': + optional: true + + '@oxlint/binding-android-arm64@1.80.0': + optional: true + + '@oxlint/binding-darwin-arm64@1.80.0': + optional: true + + '@oxlint/binding-darwin-x64@1.80.0': + optional: true + + '@oxlint/binding-freebsd-x64@1.80.0': + optional: true + + '@oxlint/binding-linux-arm-gnueabihf@1.80.0': + optional: true + + '@oxlint/binding-linux-arm-musleabihf@1.80.0': + optional: true + + '@oxlint/binding-linux-arm64-gnu@1.80.0': + optional: true + + '@oxlint/binding-linux-arm64-musl@1.80.0': + optional: true + + '@oxlint/binding-linux-ppc64-gnu@1.80.0': + optional: true + + '@oxlint/binding-linux-riscv64-gnu@1.80.0': + optional: true + + '@oxlint/binding-linux-riscv64-musl@1.80.0': + optional: true + + '@oxlint/binding-linux-s390x-gnu@1.80.0': + optional: true + + '@oxlint/binding-linux-x64-gnu@1.80.0': + optional: true + + '@oxlint/binding-linux-x64-musl@1.80.0': + optional: true + + '@oxlint/binding-openharmony-arm64@1.80.0': + optional: true + + '@oxlint/binding-win32-arm64-msvc@1.80.0': + optional: true + + '@oxlint/binding-win32-ia32-msvc@1.80.0': + optional: true + + '@oxlint/binding-win32-x64-msvc@1.80.0': + optional: true + + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.0': {} + + '@redocly/openapi-core@1.34.20(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.3.2 + minimatch: 5.1.9 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + + '@rolldown/binding-android-arm-eabi@1.2.9': + optional: true + + '@rolldown/binding-android-arm64@1.2.9': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.9': + optional: true + + '@rolldown/binding-darwin-x64@1.2.9': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.9': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.9': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.9': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.9': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.9': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.9': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.9': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.9': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.9': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.9': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.9': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tauri-apps/api@2.11.1': {} + + '@tauri-apps/cli-darwin-arm64@2.11.4': + optional: true + + '@tauri-apps/cli-darwin-x64@2.11.4': + optional: true + + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': + optional: true + + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': + optional: true + + '@tauri-apps/cli-linux-arm64-musl@2.11.4': + optional: true + + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': + optional: true + + '@tauri-apps/cli-linux-x64-gnu@2.11.4': + optional: true + + '@tauri-apps/cli-linux-x64-musl@2.11.4': + optional: true + + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': + optional: true + + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': + optional: true + + '@tauri-apps/cli-win32-x64-msvc@2.11.4': + optional: true + + '@tauri-apps/cli@2.11.4': + optionalDependencies: + '@tauri-apps/cli-darwin-arm64': 2.11.4 + '@tauri-apps/cli-darwin-x64': 2.11.4 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.11.4 + '@tauri-apps/cli-linux-arm64-gnu': 2.11.4 + '@tauri-apps/cli-linux-arm64-musl': 2.11.4 + '@tauri-apps/cli-linux-riscv64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-musl': 2.11.4 + '@tauri-apps/cli-win32-arm64-msvc': 2.11.4 + '@tauri-apps/cli-win32-ia32-msvc': 2.11.4 + '@tauri-apps/cli-win32-x64-msvc': 2.11.4 + + '@testing-library/dom@10.4.2': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/react@16.3.0(@testing-library/dom@10.4.2)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + dependencies: + '@babel/runtime': 7.29.7 + '@testing-library/dom': 10.4.2 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.5(@types/react@19.2.18) + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.2)': + dependencies: + '@testing-library/dom': 10.4.2 + + '@types/aria-query@5.0.4': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/node@26.3.0': + dependencies: + undici-types: 8.3.0 + + '@types/react-dom@19.2.5(@types/react@19.2.18)': + dependencies: + '@types/react': 19.2.18 + + '@types/react@19.2.18': + dependencies: + csstype: 3.2.3 + + '@vitejs/plugin-react@6.1.1(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.3.0(@types/node@26.3.0)(yaml@2.9.0) + + '@vitest/mocker@5.0.1(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0))': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.1 + estree-walker: 3.0.3 + magic-string: 1.4.1 + optionalDependencies: + vite: 8.3.0(@types/node@26.3.0)(yaml@2.9.0) + + '@vitest/spy@5.0.1': {} + + agent-base@7.1.4: {} + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-styles@5.2.0: {} + + argparse@2.0.1: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + assertion-error@2.0.1: {} + + balanced-match@1.0.2: {} + + brace-expansion@2.1.7: + dependencies: + balanced-match: 1.0.2 + + chai@6.2.2: {} + + change-case@5.4.4: {} + + colorette@1.4.0: {} + + cssstyle@4.6.0: + dependencies: + '@asamuzakjp/css-color': 3.2.0 + rrweb-cssom: 0.8.0 + + csstype@3.2.3: {} + + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + + debug@4.4.3(supports-color@10.2.2): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 + + decimal.js@10.6.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + dom-accessibility-api@0.5.16: {} + + entities@6.0.1: {} + + es-module-lexer@2.3.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fast-deep-equal@3.1.3: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + fsevents@2.3.3: + optional: true + + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + http-proxy-agent@7.0.2(supports-color@10.2.2): + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6(supports-color@10.2.2): + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + index-to-position@1.2.0: {} + + is-potential-custom-element-name@1.0.1: {} + + js-levenshtein@1.1.6: {} + + js-tokens@4.0.0: {} + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + jsdom@26.1.0(supports-color@10.2.2): + dependencies: + cssstyle: 4.6.0 + data-urls: 5.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2(supports-color@10.2.2) + https-proxy-agent: 7.0.6(supports-color@10.2.2) + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.27 + parse5: 7.3.0 + rrweb-cssom: 0.8.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.21.3 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + json-schema-traverse@1.0.0: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + lru-cache@10.4.3: {} + + lz-string@1.5.0: {} + + magic-string@1.4.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.7 + + ms@2.1.3: {} + + nanoid@3.3.19: {} + + nwsapi@2.2.27: {} + + obug@2.2.1: {} + + openapi-typescript@7.13.0(typescript@5.9.3): + dependencies: + '@redocly/openapi-core': 1.34.20(supports-color@10.2.2) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.2.2 + typescript: 5.9.3 + yargs-parser: 21.1.1 + + oxlint@1.80.0: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.80.0 + '@oxlint/binding-android-arm64': 1.80.0 + '@oxlint/binding-darwin-arm64': 1.80.0 + '@oxlint/binding-darwin-x64': 1.80.0 + '@oxlint/binding-freebsd-x64': 1.80.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.80.0 + '@oxlint/binding-linux-arm-musleabihf': 1.80.0 + '@oxlint/binding-linux-arm64-gnu': 1.80.0 + '@oxlint/binding-linux-arm64-musl': 1.80.0 + '@oxlint/binding-linux-ppc64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-gnu': 1.80.0 + '@oxlint/binding-linux-riscv64-musl': 1.80.0 + '@oxlint/binding-linux-s390x-gnu': 1.80.0 + '@oxlint/binding-linux-x64-gnu': 1.80.0 + '@oxlint/binding-linux-x64-musl': 1.80.0 + '@oxlint/binding-openharmony-arm64': 1.80.0 + '@oxlint/binding-win32-arm64-msvc': 1.80.0 + '@oxlint/binding-win32-ia32-msvc': 1.80.0 + '@oxlint/binding-win32-x64-msvc': 1.80.0 + + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.7 + index-to-position: 1.2.0 + type-fest: 4.41.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + pluralize@8.0.0: {} + + postcss@8.5.28: + dependencies: + nanoid: 3.3.19 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.6.2: {} + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + punycode@2.3.1: {} + + react-dom@19.2.8(react@19.2.8): + dependencies: + react: 19.2.8 + scheduler: 0.27.0 + + react-is@17.0.2: {} + + react@19.2.8: {} + + require-from-string@2.0.2: {} + + rolldown@1.2.9: + dependencies: + '@oxc-project/types': 0.150.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.9 + '@rolldown/binding-android-arm64': 1.2.9 + '@rolldown/binding-darwin-arm64': 1.2.9 + '@rolldown/binding-darwin-x64': 1.2.9 + '@rolldown/binding-freebsd-x64': 1.2.9 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.9 + '@rolldown/binding-linux-arm64-gnu': 1.2.9 + '@rolldown/binding-linux-arm64-musl': 1.2.9 + '@rolldown/binding-linux-ppc64-gnu': 1.2.9 + '@rolldown/binding-linux-s390x-gnu': 1.2.9 + '@rolldown/binding-linux-x64-gnu': 1.2.9 + '@rolldown/binding-linux-x64-musl': 1.2.9 + '@rolldown/binding-openharmony-arm64': 1.2.9 + '@rolldown/binding-win32-arm64-msvc': 1.2.9 + '@rolldown/binding-win32-x64-msvc': 1.2.9 + + rrweb-cssom@0.8.0: {} + + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + + semver@7.8.5: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@4.2.0: {} + + supports-color@10.2.2: {} + + symbol-tree@3.2.4: {} + + tinybench@6.1.4: {} + + tinyexec@1.3.0: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tldts-core@6.1.86: {} + + tldts@6.1.86: + dependencies: + tldts-core: 6.1.86 + + tough-cookie@5.1.2: + dependencies: + tldts: 6.1.86 + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tslib@2.8.1: + optional: true + + type-fest@4.41.0: {} + + typescript@5.9.3: {} + + undici-types@8.3.0: {} + + uri-js-replace@1.0.1: {} + + vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.28 + rolldown: 1.2.9 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.3.0 + fsevents: 2.3.3 + yaml: 2.9.0 + + vitest@5.0.1(@types/node@26.3.0)(jsdom@26.1.0(supports-color@10.2.2))(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.1(vite@8.3.0(@types/node@26.3.0)(yaml@2.9.0)) + chai: 6.2.2 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.1 + obug: 2.2.1 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 6.1.4 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + vite: 8.3.0(@types/node@26.3.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 26.3.0 + jsdom: 26.1.0(supports-color@10.2.2) + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.21.3: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + yaml-ast-parser@0.0.43: {} + + yaml@2.9.0: {} + + yargs-parser@21.1.1: {} diff --git a/desktop/pnpm-workspace.yaml b/desktop/pnpm-workspace.yaml new file mode 100644 index 000000000..6aebbe802 --- /dev/null +++ b/desktop/pnpm-workspace.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +allowBuilds: + sharp: true diff --git a/desktop/rust-toolchain.toml b/desktop/rust-toolchain.toml new file mode 100644 index 000000000..75433afd3 --- /dev/null +++ b/desktop/rust-toolchain.toml @@ -0,0 +1,18 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +[toolchain] +channel = "1.95.0" +targets = ["x86_64-pc-windows-msvc"] +components = ["rustfmt", "clippy"] diff --git a/desktop/scripts/generate.mjs b/desktop/scripts/generate.mjs new file mode 100644 index 000000000..4076874a6 --- /dev/null +++ b/desktop/scripts/generate.mjs @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +import { readFile, writeFile, mkdir } from "node:fs/promises"; +import { createHash } from "node:crypto"; +import { fileURLToPath } from "node:url"; +import YAML from "yaml"; +import openapiTS, { astToString } from "openapi-typescript"; + +const root = new URL("../", import.meta.url); +const contractUrl = new URL("../openapi/powercontext.yaml", root); +const raw = await readFile(contractUrl, "utf8"); +const contract = YAML.parse(raw); +const wanted = [ + "get_liveness", + "get_readiness", + "get_capabilities", + "get_access_principal", + "list_scopes", + "get_scope", + "get_default_scope", + "remember_memory", + "search_memory", + "get_memory_entry", +]; +const operations = {}; +for (const [path, item] of Object.entries(contract.paths)) { + for (const [method, op] of Object.entries(item)) { + if (wanted.includes(op?.operationId)) { + if (operations[op.operationId]) throw new Error("Duplicate operation"); + operations[op.operationId] = { method: method.toUpperCase(), path }; + } + } +} +if (Object.keys(operations).length !== wanted.length) + throw new Error("Missing public operation"); +const digest = createHash("sha256") + .update(raw.replaceAll("\r\n", "\n")) + .digest("hex"); +const license = + (await readFile(new URL(import.meta.url), "utf8")).split(" */")[0] + + " */\n\n"; +const header = + license + "// Generated from openapi/powercontext.yaml. Do not edit.\n"; +const outputs = { + "ui/src/generated/api.d.ts": header + astToString(await openapiTS(contract)), + "ui/src/generated/operations.ts": + header + + "export const contractSha256 = " + + JSON.stringify(digest) + + ";\nexport const operations = " + + JSON.stringify(operations, null, 2) + + " as const;\n", + "src-tauri/src/transport/operations.json": + JSON.stringify({ contractSha256: digest, operations }, null, 2) + "\n", +}; +for (const [name, text] of Object.entries(outputs)) { + const target = new URL(name, root); + if (process.argv.includes("--check")) { + if ((await readFile(target, "utf8")).replaceAll("\r\n", "\n") !== text) + throw new Error("Contract drift: " + name); + } else { + await mkdir(fileURLToPath(new URL(".", target)), { recursive: true }); + await writeFile(target, text); + } +} +console.log( + process.argv.includes("--check") + ? "Desktop contract matches OpenAPI." + : "Desktop contract generated.", +); diff --git a/desktop/scripts/icons.mjs b/desktop/scripts/icons.mjs new file mode 100644 index 000000000..90c421620 --- /dev/null +++ b/desktop/scripts/icons.mjs @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +import sharp from "sharp"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { execFileSync } from "node:child_process"; +const root = new URL("../", import.meta.url); +const source = new URL("../website/assets/powercontext-color.png", root); +const output = new URL("src-tauri/icons/", root); +const temporary = new URL(".artifacts/icon-generation/", root); +await mkdir(temporary, { recursive: true }); +await mkdir(output, { recursive: true }); +// Extract the project's square mark, never a screenshot or third-party logo. +const brand = await sharp(fileURLToPath(source)) + .extract({ left: 0, top: 0, width: 240, height: 240 }) + .png() + .toBuffer(); +await writeFile(new URL("brand.png", temporary), brand); +execFileSync( + process.execPath, + [ + fileURLToPath(new URL("node_modules/@tauri-apps/cli/tauri.js", root)), + "icon", + fileURLToPath(new URL("brand.png", temporary)), + "--output", + fileURLToPath(new URL("derived/", temporary)), + ], + { stdio: "pipe" }, +); +for (const name of ["brand.png", "icon.png", "icon.ico"]) { + const expected = + name === "brand.png" + ? brand + : await readFile(new URL("derived/" + name, temporary)); + const destination = new URL(name, output); + if (process.argv.includes("--check")) { + if (!(await readFile(destination)).equals(expected)) + throw new Error("Brand resource drift: " + name); + } else { + await writeFile(destination, expected); + } +} +console.log("Desktop brand resources match their canonical source."); diff --git a/desktop/scripts/windows-smoke.ps1 b/desktop/scripts/windows-smoke.ps1 new file mode 100644 index 000000000..4413a8bf6 --- /dev/null +++ b/desktop/scripts/windows-smoke.ps1 @@ -0,0 +1,65 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +# CI only: this does not qualify interactive or standard-user behavior. +$ErrorActionPreference = 'Stop' +if ($env:GITHUB_ACTIONS -ne 'true') { throw 'Run on a disposable GitHub Actions runner.' } +$desktopRoot = Split-Path -Parent $PSScriptRoot +$packages = @(Get-ChildItem -LiteralPath "$desktopRoot/src-tauri/target/release/bundle/nsis" -Filter '*-setup.exe') +if ($packages.Count -ne 1) { throw 'Expected exactly one installer.' } +$package = $packages[0] +$testRoot = Join-Path $env:RUNNER_TEMP "desktop-smoke-$([guid]::NewGuid().ToString('N'))" +$installDir = Join-Path $testRoot '中文安装目录' +$sentinel = Join-Path $testRoot 'external-data.txt' +New-Item -ItemType Directory -Path $testRoot | Out-Null +Set-Content -LiteralPath $sentinel -Value 'Synthetic external data; not a Server database.' -Encoding utf8 +$sentinelHash = (Get-FileHash -LiteralPath $sentinel).Hash +$report = [ordered]@{ + scope = 'Hosted runner; not standard-user, absent-WebView2 or visual UI qualification' + runnerImage = $env:ImageVersion + commit = $env:GITHUB_SHA + installerSha256 = (Get-FileHash -LiteralPath $package.FullName).Hash + signature = (Get-AuthenticodeSignature -LiteralPath $package.FullName).Status.ToString() + installExit = $null + uninstallExit = $null + externalSentinelPreserved = $false +} +try { + # NSIS /D must be last and unquoted, including paths with spaces. + $installer = Start-Process -FilePath $package.FullName -ArgumentList "/S /D=$installDir" -PassThru -Wait -WindowStyle Hidden + $report.installExit = $installer.ExitCode + if ($installer.ExitCode -ne 0) { throw 'Installer failed.' } + if (-not (Test-Path -LiteralPath (Join-Path $installDir 'powercontext-desktop.exe'))) { + throw 'Installed executable missing.' + } +} finally { + try { + $uninstaller = Join-Path $installDir 'uninstall.exe' + if (Test-Path -LiteralPath $uninstaller) { + $uninstall = Start-Process -FilePath $uninstaller -ArgumentList "/S _?=$installDir" -PassThru -Wait -WindowStyle Hidden + $report.uninstallExit = $uninstall.ExitCode + if ($uninstall.ExitCode -ne 0 -or (Test-Path -LiteralPath (Join-Path $installDir 'powercontext-desktop.exe'))) { + throw 'Uninstall did not remove the application.' + } + } + $report.externalSentinelPreserved = (Test-Path -LiteralPath $sentinel) -and ((Get-FileHash -LiteralPath $sentinel).Hash -eq $sentinelHash) + if (-not $report.externalSentinelPreserved) { throw 'External sentinel changed.' } + } finally { + $artifactDir = Join-Path $desktopRoot '.artifacts' + New-Item -ItemType Directory -Path $artifactDir -Force | Out-Null + $report | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $artifactDir 'windows-smoke.json') -Encoding utf8 + $report | ConvertTo-Json | Write-Output + } +} +if ($null -eq $report.uninstallExit) { throw 'Installed uninstaller was missing.' } diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock new file mode 100644 index 000000000..0a3239ed4 --- /dev/null +++ b/desktop/src-tauri/Cargo.lock @@ -0,0 +1,5227 @@ +# 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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.20", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure 0.13.2", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "aws-lc-rs" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] + +[[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 = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec 0.8.0", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +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 = "brotli" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +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.13.2", + "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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591" +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.20", +] + +[[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.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "time", + "version_check", +] + +[[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.13.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.2", + "core-foundation", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[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.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "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.119", +] + +[[package]] +name = "ctor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[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.119", +] + +[[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.119", +] + +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[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.119", +] + +[[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.13.2", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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.119", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[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 = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.6+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[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 = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[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.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[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.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[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.13.2", + "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.119", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[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.119", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[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 = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[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 = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link 0.2.1", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[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.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "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.13.2", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "keyring" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" +dependencies = [ + "byteorder", + "log", + "windows-sys 0.60.2", + "zeroize", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a" +dependencies = [ + "libc", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[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.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[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 = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "muda" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.20", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.2", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[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 = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[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.119", +] + +[[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.13.2", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.2", + "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.13.2", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[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.13.2", + "block2", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.2", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.2", + "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.13.2", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "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.13.2", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "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_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 = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[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.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plist" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896bade328c13f7042a297ea5ac5b0951f6cf989dea5f32c2fd98da398195cb" +dependencies = [ + "base64 0.23.1", + "indexmap 2.14.2", + "quick-xml", + "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 0.8.9", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powercontext-desktop" +version = "0.1.0" +dependencies = [ + "keyring", + "native-tls", + "rcgen", + "reqwest 0.12.28", + "rustls", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tokio", + "tokio-rustls", + "ts-rs", + "url", + "zeroize", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.15+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-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +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 = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rcgen" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_users" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" +dependencies = [ + "libredox", + "thiserror 2.0.20", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[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", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +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.119", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.2", + "core-foundation", + "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.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.13.2", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "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.119", +] + +[[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.119", +] + +[[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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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.119", +] + +[[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 = "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 = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +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 = "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", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e" +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", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" +dependencies = [ + "bitflags 2.13.2", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "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.119", +] + +[[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.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d059f2527558d9dba6f186dec4772610e1aecfd3f94002397613e7e648752b66" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest 0.13.5", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.20", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be9aa8c59a894f76c29a002501c589de5eb4987a5913d62a6e0a47f320901988" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" +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.119", + "tauri-utils", + "thiserror 2.0.20", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-runtime" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.20", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dom_query", + "dunce", + "glob", + "http", + "infer", + "json-patch", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.20", + "toml 1.1.6+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.6+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.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" +dependencies = [ + "new_debug_unreachable", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[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.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.52.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.2", + "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" +version = "1.1.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" +dependencies = [ + "indexmap 2.14.2", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + +[[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.14.2", + "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.14.2", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.15+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +dependencies = [ + "indexmap 2.14.2", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[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.4", +] + +[[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", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.2", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[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-core", +] + +[[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.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.20", + "windows-sys 0.61.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ts-rs" +version = "12.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756050066659291d47a554a9f558125db17428b073c5ffce1daf5dcb0f7231d8" +dependencies = [ + "thiserror 2.0.20", + "ts-rs-macros", +] + +[[package]] +name = "ts-rs-macros" +version = "12.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d90eea51bc7988ef9e674bf80a85ba6804739e535e9cab48e4bb34a8b652aa" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "termcolor", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[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.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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.20", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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.119", +] + +[[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-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[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.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "wry" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "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.20", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.20", + "time", +] + +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec 0.9.1", + "time", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure 0.14.0", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure 0.14.0", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml new file mode 100644 index 000000000..b89d704b9 --- /dev/null +++ b/desktop/src-tauri/Cargo.toml @@ -0,0 +1,50 @@ +# Copyright (c) 2026 OceanBase. +# +# 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 +# +# http://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. + +[package] +name = "powercontext-desktop" +version = "0.1.0" +edition = "2024" +rust-version = "1.95" +license = "Apache-2.0" +default-run = "powercontext-desktop" + +[lib] +name = "powercontext_desktop" + +[features] +custom-protocol = ["tauri/custom-protocol"] + +[build-dependencies] +tauri-build = { version = "=2.6.0", features = [] } + +[dependencies] +tauri = { version = "=2.11.0", features = [] } +serde = { version = "=1.0.228", features = ["derive"] } +serde_json = "=1.0.149" +ts-rs = "=12.0.1" +reqwest = { version = "=0.12.28", default-features = false, features = ["native-tls", "json", "stream"] } +url = "=2.5.8" +tokio = { version = "=1.52.1", features = ["macros", "rt-multi-thread", "net", "io-util", "sync", "time"] } +zeroize = "=1.8.2" +native-tls = "=0.2.18" + +[target.'cfg(windows)'.dependencies] +keyring = { version = "=3.6.3", default-features = false, features = ["windows-native"] } + +[dev-dependencies] +tauri = { version = "=2.11.0", features = ["test"] } +rcgen = "=0.14.8" +tokio-rustls = "=0.26.4" +rustls = { version = "=0.23.40", default-features = false, features = ["ring", "std", "tls12"] } diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs new file mode 100644 index 000000000..2569af081 --- /dev/null +++ b/desktop/src-tauri/build.rs @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +fn main() { + // Integration-test executables also need ComCtl32 v6 for Tauri's menu imports. + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") { + println!("cargo:rustc-link-arg-tests=/MANIFEST:EMBED"); + println!( + "cargo:rustc-link-arg-tests=/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'" + ); + } + tauri_build::try_build( + tauri_build::Attributes::new() + .app_manifest(tauri_build::AppManifest::new().commands(&["foundation_info"])), + ) + .expect("desktop build configuration is invalid"); +} diff --git a/desktop/src-tauri/capabilities/main.json b/desktop/src-tauri/capabilities/main.json new file mode 100644 index 000000000..e39dcf66b --- /dev/null +++ b/desktop/src-tauri/capabilities/main.json @@ -0,0 +1,11 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "main", + "description": "Only the packaged main window can read the safe foundation status.", + "windows": [ + "main" + ], + "permissions": [ + "allow-foundation-info" + ] +} diff --git a/desktop/src-tauri/examples/credential_probe.rs b/desktop/src-tauri/examples/credential_probe.rs new file mode 100644 index 000000000..9ce34a24d --- /dev/null +++ b/desktop/src-tauri/examples/credential_probe.rs @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +//! Opt-in native test. Stores only a synthetic marker under a unique test ID, then removes it. +use powercontext_desktop::credentials::{CredentialId, Secret, Vault, WindowsVault}; +fn main() { + let args: Vec = std::env::args().collect(); + if args.get(1).is_some_and(|s| s == "read") { + let id = CredentialId::new(args[2].clone()).unwrap(); + // Loading a valid secret after process restart proves it remained in the OS vault. + WindowsVault + .read(&id) + .expect("native credential read failed"); + return; + } + let nonce = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + let name = format!("s1-probe-{}-{nonce}", std::process::id()); + let id = CredentialId::new(name.clone()).unwrap(); + WindowsVault + .put( + &id, + &Secret::new("synthetic-s1-credential-only".into()).unwrap(), + ) + .expect("native credential write failed"); + let result = std::process::Command::new(std::env::current_exe().unwrap()) + .args(["read", &name]) + .status(); + let cleanup = WindowsVault.delete(&id); + cleanup.expect("test credential cleanup failed"); + assert!(result.unwrap().success(), "child read failed"); + assert!( + WindowsVault.read(&id).is_err(), + "test credential was not removed" + ); + println!("PASS: Windows vault write, new-process read, delete; no secret returned."); +} diff --git a/desktop/src-tauri/examples/export_ipc.rs b/desktop/src-tauri/examples/export_ipc.rs new file mode 100644 index 000000000..2a45acca8 --- /dev/null +++ b/desktop/src-tauri/examples/export_ipc.rs @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use powercontext_desktop::{ + credentials::{CredentialWriteReceipt, CredentialWriteRequest, StorageChoice}, + error::SafeError, + ipc::FoundationInfo, +}; +use ts_rs::TS; +fn main() { + let config = ts_rs::Config::default(); + let license = include_str!("export_ipc.rs") + .split(" */") + .next() + .unwrap() + .to_owned() + + " */\n\n"; + let output = license + + &format!( + "// Generated from Rust IPC types. Do not edit.\nexport {}\nexport {}\nexport {}\nexport {}\nexport {}\n", + SafeError::decl(&config), + FoundationInfo::decl(&config), + StorageChoice::decl(&config), + CredentialWriteRequest::decl(&config), + CredentialWriteReceipt::decl(&config) + ); + let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../ui/src/generated/ipc.ts"); + if std::env::args().any(|arg| arg == "--check") { + assert_eq!( + std::fs::read_to_string(path).unwrap().replace("\r\n", "\n"), + output, + "IPC drift: run cargo run --example export_ipc" + ); + } else { + std::fs::write(path, output).unwrap(); + } +} diff --git a/desktop/src-tauri/icons/brand.png b/desktop/src-tauri/icons/brand.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ac6be4452b941c9178ccc0227962b7cce7041f GIT binary patch literal 4288 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 +impl Secret { + pub fn new(value: String) -> Result { + let value = Zeroizing::new(value); + if value.is_empty() || value.len() > 2048 || !value.bytes().all(|c| c.is_ascii_graphic()) { + return Err(SafeError::InvalidCredential); + } + Ok(Self(value)) + } + pub(crate) fn expose(&self) -> &str { + &self.0 + } +} + +impl<'de> Deserialize<'de> for Secret { + fn deserialize>(deserializer: D) -> Result { + let value = String::deserialize(deserializer)?; + Self::new(value).map_err(|_| serde::de::Error::custom("invalid credential")) + } +} + +/// IDs must be native-generated opaque identifiers, never endpoints or account names. +pub struct CredentialId(String); +impl CredentialId { + pub fn new(id: String) -> Result { + if id.is_empty() + || id.len() > 80 + || !id.bytes().all(|c| c.is_ascii_alphanumeric() || c == b'-') + { + return Err(SafeError::InvalidCredential); + } + Ok(Self(id)) + } +} + +pub trait Vault { + fn put(&self, id: &CredentialId, secret: &Secret) -> Result<(), SafeError>; + fn read(&self, id: &CredentialId) -> Result; + fn delete(&self, id: &CredentialId) -> Result<(), SafeError>; +} + +pub struct WindowsVault; +#[cfg(windows)] +impl WindowsVault { + fn entry(id: &CredentialId) -> Result { + keyring::Entry::new(SERVICE, &id.0).map_err(|_| SafeError::CredentialUnavailable) + } +} +#[cfg(windows)] +impl Vault for WindowsVault { + fn put(&self, id: &CredentialId, secret: &Secret) -> Result<(), SafeError> { + Self::entry(id)? + .set_password(secret.expose()) + .map_err(|_| SafeError::CredentialUnavailable) + } + fn read(&self, id: &CredentialId) -> Result { + let value = Self::entry(id)?.get_password().map_err(|e| match e { + keyring::Error::NoEntry => SafeError::CredentialMissing, + _ => SafeError::CredentialUnavailable, + })?; + Secret::new(value) + } + fn delete(&self, id: &CredentialId) -> Result<(), SafeError> { + match Self::entry(id)?.delete_credential() { + Ok(()) | Err(keyring::Error::NoEntry) => Ok(()), + Err(_) => Err(SafeError::CredentialUnavailable), + } + } +} +#[cfg(not(windows))] +impl Vault for WindowsVault { + fn put(&self, _: &CredentialId, _: &Secret) -> Result<(), SafeError> { + Err(SafeError::CredentialUnavailable) + } + fn read(&self, _: &CredentialId) -> Result { + Err(SafeError::CredentialUnavailable) + } + fn delete(&self, _: &CredentialId) -> Result<(), SafeError> { + Err(SafeError::CredentialUnavailable) + } +} + +#[derive(Clone, Copy, Deserialize, Serialize, TS)] +#[serde(rename_all = "snake_case")] +pub enum StorageChoice { + Persistent, + SessionOnly, +} +/// Renderer-to-native input only. There is deliberately no Serialize or Debug implementation. +/// S2 must resolve the native-owned connection ID before consuming this request. +#[derive(Deserialize, TS)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct CredentialWriteRequest { + #[ts(type = "string")] + secret: Secret, + storage: StorageChoice, +} + +/// The entire successful write response; neither a secret nor its vault identifier is exposed. +#[derive(Serialize, TS)] +pub struct CredentialWriteReceipt { + storage: StorageChoice, +} + +impl CredentialWriteRequest { + pub fn store( + self, + vault: &impl Vault, + native_id: CredentialId, + ) -> Result<(Credential, CredentialWriteReceipt), SafeError> { + let credential = Credential::store(vault, native_id, self.secret, self.storage)?; + Ok(( + credential, + CredentialWriteReceipt { + storage: self.storage, + }, + )) + } +} + +pub enum Credential { + Persistent(CredentialId), + SessionOnly(Secret), +} +impl Credential { + /// Failure is returned to the caller; session storage requires a separate explicit choice. + pub fn store( + vault: &impl Vault, + id: CredentialId, + secret: Secret, + choice: StorageChoice, + ) -> Result { + match choice { + StorageChoice::Persistent => { + vault.put(&id, &secret)?; + Ok(Self::Persistent(id)) + } + StorageChoice::SessionOnly => Ok(Self::SessionOnly(secret)), + } + } + pub fn load(&self, vault: &impl Vault) -> Result { + match self { + Self::Persistent(id) => vault.read(id), + Self::SessionOnly(secret) => Secret::new(secret.expose().to_owned()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + struct Unavailable; + impl Vault for Unavailable { + fn put(&self, _: &CredentialId, _: &Secret) -> Result<(), SafeError> { + Err(SafeError::CredentialUnavailable) + } + fn read(&self, _: &CredentialId) -> Result { + Err(SafeError::CredentialUnavailable) + } + fn delete(&self, _: &CredentialId) -> Result<(), SafeError> { + Err(SafeError::CredentialUnavailable) + } + } + #[test] + fn write_protocol_requires_explicit_storage_and_returns_only_metadata() { + for input in [ + r#"{"secret":"synthetic"}"#, + r#"{"secret":"synthetic","storage":"automatic"}"#, + r#"{"secret":"synthetic","storage":"session_only","nativeId":"chosen"}"#, + ] { + assert!(serde_json::from_str::(input).is_err()); + } + let invalid = serde_json::from_str::( + r#"{"secret":"private value","storage":"persistent"}"#, + ); + let error = invalid.err().unwrap().to_string(); + assert!(!error.contains("private value")); + let persistent: CredentialWriteRequest = + serde_json::from_str(r#"{"secret":"synthetic","storage":"persistent"}"#).unwrap(); + assert!(matches!( + persistent.store(&Unavailable, CredentialId::new("native".into()).unwrap()), + Err(SafeError::CredentialUnavailable) + )); + let session: CredentialWriteRequest = + serde_json::from_str(r#"{"secret":"synthetic","storage":"session_only"}"#).unwrap(); + let (credential, receipt) = session + .store(&Unavailable, CredentialId::new("native".into()).unwrap()) + .unwrap(); + assert_eq!(credential.load(&Unavailable).unwrap().expose(), "synthetic"); + assert_eq!( + serde_json::to_value(receipt).unwrap(), + serde_json::json!({"storage":"session_only"}) + ); + } + + #[test] + fn unavailable_vault_never_silently_downgrades() { + let result = Credential::store( + &Unavailable, + CredentialId::new("test".into()).unwrap(), + Secret::new("synthetic".into()).unwrap(), + StorageChoice::Persistent, + ); + assert!(matches!(result, Err(SafeError::CredentialUnavailable))); + let session = Credential::store( + &Unavailable, + CredentialId::new("test".into()).unwrap(), + Secret::new("synthetic".into()).unwrap(), + StorageChoice::SessionOnly, + ) + .unwrap(); + assert_eq!(session.load(&Unavailable).unwrap().expose(), "synthetic"); + } +} diff --git a/desktop/src-tauri/src/error.rs b/desktop/src-tauri/src/error.rs new file mode 100644 index 000000000..9485f1744 --- /dev/null +++ b/desktop/src-tauri/src/error.rs @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use serde::Serialize; +use ts_rs::TS; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, TS)] +#[serde(rename_all = "snake_case")] +pub enum SafeError { + UnauthorizedWindow, + InvalidEndpoint, + InsecureTransport, + InvalidCertificate, + CredentialUnavailable, + CredentialMissing, + InvalidCredential, + Timeout, + Tls, + Network, + Redirect, + Unauthorized, + Forbidden, + Server, + InvalidResponse, + ResponseTooLarge, + Busy, +} diff --git a/desktop/src-tauri/src/ipc.rs b/desktop/src-tauri/src/ipc.rs new file mode 100644 index 000000000..ce5ae46a9 --- /dev/null +++ b/desktop/src-tauri/src/ipc.rs @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use crate::error::SafeError; +use serde::Serialize; +use ts_rs::TS; + +#[derive(Serialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct FoundationInfo { + pub version: String, + pub phase: String, + pub credential_backend: String, + pub server_connected: bool, +} + +pub fn authorize_window(label: &str) -> Result<(), SafeError> { + if label == "main" { + Ok(()) + } else { + Err(SafeError::UnauthorizedWindow) + } +} + +#[tauri::command] +pub fn foundation_info( + window: tauri::WebviewWindow, +) -> Result { + authorize_window(window.label())?; + Ok(FoundationInfo { + version: env!("CARGO_PKG_VERSION").into(), + phase: "S1".into(), + credential_backend: if cfg!(windows) { + "windows_credential_manager" + } else { + "unavailable" + } + .into(), + server_connected: false, + }) +} + +pub fn allowed_navigation(url: &url::Url) -> bool { + let packaged = + url.scheme() == "http" && url.host_str() == Some("tauri.localhost") && url.port().is_none(); + let development = + cfg!(debug_assertions) && url.origin().ascii_serialization() == "http://127.0.0.1:1420"; + (packaged || development) && url.username().is_empty() && url.password().is_none() +} diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs new file mode 100644 index 000000000..dff969398 --- /dev/null +++ b/desktop/src-tauri/src/lib.rs @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +pub mod credentials; +pub mod error; +pub mod ipc; +pub mod transport; + +pub fn run() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![ipc::foundation_info]) + .setup(|app| { + let config = &app.config().app.windows[0]; + tauri::WebviewWindowBuilder::from_config(app, config)? + .on_navigation(ipc::allowed_navigation) + .build()?; + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("desktop host failed"); +} diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs new file mode 100644 index 000000000..d59c8e5e2 --- /dev/null +++ b/desktop/src-tauri/src/main.rs @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +fn main() { + powercontext_desktop::run(); +} diff --git a/desktop/src-tauri/src/transport/mod.rs b/desktop/src-tauri/src/transport/mod.rs new file mode 100644 index 000000000..7f655a994 --- /dev/null +++ b/desktop/src-tauri/src/transport/mod.rs @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +//! Only native adapters use this transport; it is not an IPC fetch primitive. +use crate::{credentials::Secret, error::SafeError}; +use reqwest::{ + Certificate, Client, + header::{AUTHORIZATION, HeaderValue}, + redirect::Policy, +}; +use std::{error::Error, sync::Arc, time::Duration}; +use tokio::sync::Semaphore; +use url::{Host, Url}; + +pub const CONNECT_TIMEOUT: Duration = Duration::from_secs(5); +pub const REQUEST_TIMEOUT: Duration = Duration::from_secs(15); +pub const MAX_RESPONSE_BYTES: usize = 1024 * 1024; +pub const MAX_CONCURRENT_READS: usize = 4; + +#[derive(Clone)] +pub struct Endpoint(Url); +impl Endpoint { + pub fn parse(raw: &str) -> Result { + // Reject ambiguous input before WHATWG URL normalization can erase it. + if raw.len() > 2048 + || raw.trim() != raw + || raw.contains(['\\', '?', '#']) + || raw.bytes().any(|c| c.is_ascii_control()) + { + return Err(SafeError::InvalidEndpoint); + } + let scheme_end = raw.find("://").ok_or(SafeError::InvalidEndpoint)? + 3; + let tail = &raw[scheme_end..]; + if tail.split('/').next().unwrap_or("").contains('@') { + return Err(SafeError::InvalidEndpoint); + } + let raw_path = tail.find('/').map(|i| &tail[i..]).unwrap_or(""); + if raw_path.split('/').any(|s| s == "." || s == "..") || raw_path.contains('%') { + return Err(SafeError::InvalidEndpoint); + } + let mut url = Url::parse(raw).map_err(|_| SafeError::InvalidEndpoint)?; + if !url.username().is_empty() || url.password().is_some() || url.host().is_none() { + return Err(SafeError::InvalidEndpoint); + } + let loopback = match url.host() { + Some(Host::Domain(host)) => host.eq_ignore_ascii_case("localhost"), + Some(Host::Ipv4(ip)) => ip.is_loopback(), + Some(Host::Ipv6(ip)) => ip.is_loopback(), + _ => false, + }; + match url.scheme() { + "https" => (), + "http" if loopback => (), + "http" => return Err(SafeError::InsecureTransport), + _ => return Err(SafeError::InvalidEndpoint), + } + let path = format!("{}/", url.path().trim_end_matches('/')); + url.set_path(&path); + Ok(Self(url)) + } + pub fn as_str(&self) -> &str { + self.0.as_str() + } + fn operation_url(&self, operation: &str) -> Result { + let manifest: serde_json::Value = serde_json::from_str(include_str!("operations.json")) + .map_err(|_| SafeError::InvalidResponse)?; + let path = manifest["operations"][operation]["path"] + .as_str() + .ok_or(SafeError::InvalidResponse)?; + self.0 + .join(path.trim_start_matches('/')) + .map_err(|_| SafeError::InvalidEndpoint) + } +} + +#[derive(Clone)] +pub struct Transport { + client: Client, + slots: Arc, +} +impl Transport { + pub fn new(ca_pem: Option<&[u8]>) -> Result { + let mut builder = Client::builder() + .no_proxy() + .redirect(Policy::none()) + .connect_timeout(CONNECT_TIMEOUT) + .timeout(REQUEST_TIMEOUT) + .referer(false); + if let Some(pem) = ca_pem { + if pem.len() > 64 * 1024 { + return Err(SafeError::InvalidCertificate); + } + let cert = Certificate::from_pem(pem).map_err(|_| SafeError::InvalidCertificate)?; + builder = builder.add_root_certificate(cert); + } + Ok(Self { + client: builder.build().map_err(|_| SafeError::Tls)?, + slots: Arc::new(Semaphore::new(MAX_CONCURRENT_READS)), + }) + } + /// S1 feasibility probe. Does not infer compatibility, authorization or readiness. + pub async fn liveness( + &self, + endpoint: &Endpoint, + credential: Option<&Secret>, + ) -> Result<(), SafeError> { + let _permit = self.slots.try_acquire().map_err(|_| SafeError::Busy)?; + let mut request = self.client.get(endpoint.operation_url("get_liveness")?); + if let Some(secret) = credential { + let mut header = HeaderValue::from_str(&format!("Bearer {}", secret.expose())) + .map_err(|_| SafeError::InvalidCredential)?; + header.set_sensitive(true); + request = request.header(AUTHORIZATION, header); + } + let mut response = request.send().await.map_err(safe_network_error)?; + match response.status().as_u16() { + 200 => (), + 300..=399 => return Err(SafeError::Redirect), + 401 => return Err(SafeError::Unauthorized), + 403 => return Err(SafeError::Forbidden), + 500..=599 => return Err(SafeError::Server), + _ => return Err(SafeError::InvalidResponse), + } + if response + .content_length() + .is_some_and(|n| n > MAX_RESPONSE_BYTES as u64) + { + return Err(SafeError::ResponseTooLarge); + } + let mut body = Vec::new(); + while let Some(chunk) = response.chunk().await.map_err(safe_network_error)? { + if body.len() + chunk.len() > MAX_RESPONSE_BYTES { + return Err(SafeError::ResponseTooLarge); + } + body.extend_from_slice(&chunk); + } + let value: serde_json::Value = + serde_json::from_slice(&body).map_err(|_| SafeError::InvalidResponse)?; + if value.get("status").and_then(|s| s.as_str()) != Some("ok") { + return Err(SafeError::InvalidResponse); + } + Ok(()) + } +} +fn safe_network_error(error: reqwest::Error) -> SafeError { + if error.is_timeout() { + return SafeError::Timeout; + } + // native-tls preserves its typed error in the source chain; never serialize its text. + let mut source = error.source(); + while let Some(cause) = source { + if cause.is::() { + return SafeError::Tls; + } + source = cause.source(); + } + SafeError::Network +} diff --git a/desktop/src-tauri/src/transport/operations.json b/desktop/src-tauri/src/transport/operations.json new file mode 100644 index 000000000..e63cc4d2e --- /dev/null +++ b/desktop/src-tauri/src/transport/operations.json @@ -0,0 +1,45 @@ +{ + "contractSha256": "de9750808e12e7a6c7a88b736b5368ba3b7c5fcf3c986f1c8cb762b66afce03c", + "operations": { + "get_liveness": { + "method": "GET", + "path": "/health/live" + }, + "get_readiness": { + "method": "GET", + "path": "/health/ready" + }, + "get_capabilities": { + "method": "GET", + "path": "/v1/capabilities" + }, + "list_scopes": { + "method": "GET", + "path": "/v1/scopes" + }, + "get_scope": { + "method": "GET", + "path": "/v1/scopes/{scope_id}" + }, + "get_default_scope": { + "method": "GET", + "path": "/v1/scopes/default" + }, + "remember_memory": { + "method": "POST", + "path": "/v1/memory/remember" + }, + "search_memory": { + "method": "POST", + "path": "/v1/memory/search" + }, + "get_memory_entry": { + "method": "POST", + "path": "/v1/memory/entries/get" + }, + "get_access_principal": { + "method": "GET", + "path": "/v1/access/me" + } + } +} diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json new file mode 100644 index 000000000..9333965a8 --- /dev/null +++ b/desktop/src-tauri/tauri.conf.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "PowerContext Desktop Preview", + "version": "0.1.0", + "identifier": "com.powercontext.desktop.preview", + "build": { + "beforeDevCommand": "pnpm dev", + "devUrl": "http://127.0.0.1:1420", + "beforeBuildCommand": "pnpm build", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "label": "main", + "title": "PowerContext Desktop", + "width": 1180, + "height": 800, + "minWidth": 400, + "minHeight": 400, + "dragDropEnabled": false, + "zoomHotkeysEnabled": true, + "create": false + } + ], + "security": { + "capabilities": [ + "main" + ], + "csp": "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src ipc: http://ipc.localhost; font-src 'self'; object-src 'none'; base-uri 'none'; frame-src 'none'; form-action 'none'", + "devCsp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src ipc: http://ipc.localhost ws://127.0.0.1:1420; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'" + } + }, + "bundle": { + "active": true, + "targets": [ + "nsis" + ], + "icon": [ + "icons/icon.ico" + ], + "publisher": "PowerContext", + "shortDescription": "Internal desktop foundation preview", + "windows": { + "nsis": { + "installMode": "currentUser", + "languages": [ + "English", + "SimpChinese" + ], + "displayLanguageSelector": true + }, + "webviewInstallMode": { + "type": "downloadBootstrapper", + "silent": true + } + } + } +} diff --git a/desktop/src-tauri/tests/ipc.rs b/desktop/src-tauri/tests/ipc.rs new file mode 100644 index 000000000..1b7c0374a --- /dev/null +++ b/desktop/src-tauri/tests/ipc.rs @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use powercontext_desktop::ipc::allowed_navigation; +use tauri::{ + ipc::{CallbackFn, InvokeBody}, + test::{INVOKE_KEY, get_ipc_response, mock_builder}, + webview::InvokeRequest, +}; + +#[test] +fn permissions_reject_untrusted_window_origin_and_arbitrary_commands() { + let app = mock_builder() + .invoke_handler(tauri::generate_handler![ + powercontext_desktop::ipc::foundation_info + ]) + .build(tauri::generate_context!()) + .unwrap(); + for (label, origin, command, allowed) in [ + ("main", "http://tauri.localhost", "foundation_info", true), + ("other", "http://tauri.localhost", "foundation_info", false), + ("main", "https://evil.example", "foundation_info", false), + ( + "main", + "http://tauri.localhost", + "plugin:shell|execute", + false, + ), + ("main", "http://tauri.localhost", "fetch", false), + ("main", "http://tauri.localhost", "credential_read", false), + ] { + use tauri::Manager; + let window = app.get_webview_window(label).unwrap_or_else(|| { + tauri::WebviewWindowBuilder::new(&app, label, Default::default()) + .build() + .unwrap() + }); + let result = get_ipc_response( + &window, + InvokeRequest { + cmd: command.into(), + callback: CallbackFn(0), + error: CallbackFn(1), + url: origin.parse().unwrap(), + body: InvokeBody::default(), + headers: Default::default(), + invoke_key: INVOKE_KEY.into(), + }, + ); + assert_eq!( + result.is_ok(), + allowed, + "{label} {origin} {command}: {result:?}" + ); + } +} +#[test] +fn blocks_remote_navigation_and_userinfo() { + for url in [ + "https://evil.example", + "file:///C:/secret", + "javascript:alert(1)", + "http://tauri.localhost.evil", + "http://user@tauri.localhost", + ] { + assert!(!allowed_navigation(&url.parse().unwrap())); + } + assert!(allowed_navigation( + &"http://tauri.localhost/".parse().unwrap() + )); +} diff --git a/desktop/src-tauri/tests/tls.rs b/desktop/src-tauri/tests/tls.rs new file mode 100644 index 000000000..a52d59eaa --- /dev/null +++ b/desktop/src-tauri/tests/tls.rs @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use powercontext_desktop::{ + error::SafeError, + transport::{Endpoint, Transport}, +}; +use rcgen::{ + BasicConstraints, CertificateParams, ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, + KeyUsagePurpose, +}; +use rustls::pki_types::PrivatePkcs8KeyDer; +use std::sync::Arc; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpListener, +}; +use tokio_rustls::TlsAcceptor; + +async fn https_fixture(hostname: &str) -> (Endpoint, String, tokio::task::JoinHandle<()>) { + let _ = rustls::crypto::ring::default_provider().install_default(); + let mut ca = CertificateParams::new(vec![]).unwrap(); + ca.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); + ca.distinguished_name + .push(rcgen::DnType::CommonName, "S1 fixture CA"); + ca.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign]; + let ca_key = KeyPair::generate().unwrap(); + let ca_cert = ca.self_signed(&ca_key).unwrap(); + let issuer = Issuer::new(ca, ca_key); + let mut leaf = CertificateParams::new(vec![hostname.into()]).unwrap(); + leaf.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; + let leaf_key = KeyPair::generate().unwrap(); + let leaf_cert = leaf.signed_by(&leaf_key, &issuer).unwrap(); + let config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_single_cert( + vec![leaf_cert.der().clone(), ca_cert.der().clone()], + PrivatePkcs8KeyDer::from(leaf_key.serialize_der()).into(), + ) + .unwrap(); + let acceptor = TlsAcceptor::from(Arc::new(config)); + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let endpoint = Endpoint::parse(&format!( + "https://127.0.0.1:{}", + listener.local_addr().unwrap().port() + )) + .unwrap(); + let task = tokio::spawn(async move { + let (stream, _) = listener.accept().await.unwrap(); + if let Ok(mut tls) = acceptor.accept(stream).await { + let mut request = [0; 4096]; + if tls.read(&mut request).await.is_ok() { + let body = r#"{"status":"ok"}"#; + let _ = tls.write_all(format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", body.len()).as_bytes()).await; + let _ = tls.shutdown().await; + } + } + }); + (endpoint, ca_cert.pem(), task) +} + +#[tokio::test] +async fn explicit_ca_is_connection_local_and_hostname_is_still_verified() { + let (endpoint, ca, task) = https_fixture("127.0.0.1").await; + Transport::new(Some(ca.as_bytes())) + .unwrap() + .liveness(&endpoint, None) + .await + .unwrap(); + task.await.unwrap(); + + let (endpoint, _, task) = https_fixture("127.0.0.1").await; + assert_eq!( + Transport::new(None) + .unwrap() + .liveness(&endpoint, None) + .await, + Err(SafeError::Tls) + ); + task.await.unwrap(); + + let (endpoint, ca, task) = https_fixture("wrong.example").await; + assert_eq!( + Transport::new(Some(ca.as_bytes())) + .unwrap() + .liveness(&endpoint, None) + .await, + Err(SafeError::Tls) + ); + task.await.unwrap(); +} diff --git a/desktop/src-tauri/tests/transport.rs b/desktop/src-tauri/tests/transport.rs new file mode 100644 index 000000000..dd9a4ca7e --- /dev/null +++ b/desktop/src-tauri/tests/transport.rs @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +use powercontext_desktop::{ + credentials::Secret, + error::SafeError, + transport::{Endpoint, MAX_RESPONSE_BYTES, Transport}, +}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpListener, +}; + +async fn fixture(response: String) -> (Endpoint, tokio::task::JoinHandle) { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let endpoint = Endpoint::parse(&format!( + "http://{}/proxy/powercontext", + listener.local_addr().unwrap() + )) + .unwrap(); + let task = tokio::spawn(async move { + let (mut stream, _) = listener.accept().await.unwrap(); + let mut request = vec![0; 8192]; + let count = stream.read(&mut request).await.unwrap(); + stream.write_all(response.as_bytes()).await.unwrap(); + String::from_utf8_lossy(&request[..count]).into_owned() + }); + (endpoint, task) +} +fn response(status: &str, body: &str) -> String { + format!( + "HTTP/1.1 {status}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", + body.len() + ) +} + +#[tokio::test] +async fn read_budget_rejects_excess_work_and_recovers_after_cancellation() { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let endpoint = Endpoint::parse(&format!("http://{}", listener.local_addr().unwrap())).unwrap(); + let (accepted, mut observed) = tokio::sync::mpsc::channel(4); + let server = tokio::spawn(async move { + let mut sockets = Vec::new(); + loop { + let (socket, _) = listener.accept().await.unwrap(); + sockets.push(socket); + if accepted.send(()).await.is_err() { + break; + } + } + }); + let transport = Transport::new(None).unwrap(); + let mut requests = Vec::new(); + for _ in 0..4 { + let client = transport.clone(); + let endpoint = endpoint.clone(); + requests.push(tokio::spawn(async move { + client.liveness(&endpoint, None).await + })); + tokio::time::timeout(std::time::Duration::from_secs(5), observed.recv()) + .await + .unwrap() + .unwrap(); + } + assert_eq!( + transport.liveness(&endpoint, None).await, + Err(SafeError::Busy) + ); + for request in requests { + request.abort(); + let _ = request.await; + } + server.abort(); + let (endpoint, server) = fixture(response("200 OK", r#"{"status":"ok"}"#)).await; + transport.liveness(&endpoint, None).await.unwrap(); + server.await.unwrap(); +} + +#[tokio::test] +async fn ignores_proxy_environment() { + if let Ok(url) = std::env::var("S1_CHILD_ENDPOINT") { + Transport::new(None) + .unwrap() + .liveness(&Endpoint::parse(&url).unwrap(), None) + .await + .unwrap(); + return; + } + let (endpoint, server) = fixture(response("200 OK", r#"{"status":"ok"}"#)).await; + let url = endpoint.as_str().to_owned(); + let child = tokio::task::spawn_blocking(move || { + std::process::Command::new(std::env::current_exe().unwrap()) + .args(["--exact", "ignores_proxy_environment"]) + .env("S1_CHILD_ENDPOINT", url) + .env("HTTP_PROXY", "http://127.0.0.1:1") + .env("HTTPS_PROXY", "http://127.0.0.1:1") + .env("ALL_PROXY", "http://127.0.0.1:1") + .env("NO_PROXY", "") + .status() + .unwrap() + }); + assert!(child.await.unwrap().success()); + server.await.unwrap(); +} + +#[tokio::test] +async fn stalled_response_times_out() { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let endpoint = Endpoint::parse(&format!("http://{}", listener.local_addr().unwrap())).unwrap(); + let server = tokio::spawn(async move { + let (_stream, _) = listener.accept().await.unwrap(); + std::future::pending::<()>().await; + }); + assert_eq!( + Transport::new(None) + .unwrap() + .liveness(&endpoint, None) + .await, + Err(SafeError::Timeout) + ); + server.abort(); +} + +#[tokio::test] +async fn rejects_chunked_overflow_without_silent_truncation() { + let body = "x".repeat(MAX_RESPONSE_BYTES + 1); + let (endpoint, server) = fixture(format!( + "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n{:x}\r\n{}\r\n0\r\n\r\n", + body.len(), + body + )) + .await; + assert_eq!( + Transport::new(None) + .unwrap() + .liveness(&endpoint, None) + .await, + Err(SafeError::ResponseTooLarge) + ); + let _ = server.await; +} +#[test] +fn shared_loopback_policy_and_unsafe_addresses() { + let vectors: serde_json::Value = serde_json::from_str(include_str!( + "../../../tests/fixtures/transport_loopback_vectors.json" + )) + .unwrap(); + for host in vectors["loopback"].as_array().unwrap() { + assert!(Endpoint::parse(&format!("http://{}:8000", host.as_str().unwrap())).is_ok()); + } + for host in vectors["non_loopback"].as_array().unwrap() { + assert!(matches!( + Endpoint::parse(&format!("http://{}:8000", host.as_str().unwrap())), + Err(SafeError::InsecureTransport) + )); + } + for bad in [ + "https://user:secret@example.com", + "https://@example.com", + "https://example.com?x=1", + "https://example.com/#hash", + "https://example.com/a/../b", + "https://example.com/%2e%2e/b", + "https://example.com/a\\b", + "file:///tmp/x", + " https://example.com", + "https://example.com/\n", + ] { + assert!(Endpoint::parse(bad).is_err(), "{bad}"); + } +} +#[tokio::test] +async fn preserves_reverse_proxy_path_and_keeps_auth_in_headers() { + let (endpoint, server) = fixture(response("200 OK", r#"{"status":"ok"}"#)).await; + Transport::new(None) + .unwrap() + .liveness( + &endpoint, + Some(&Secret::new("synthetic-test-only".into()).unwrap()), + ) + .await + .unwrap(); + let request = server.await.unwrap(); + assert!(request.starts_with("GET /proxy/powercontext/health/live HTTP/1.1")); + assert!( + request + .to_lowercase() + .contains("authorization: bearer synthetic-test-only") + ); + assert!(!request.lines().next().unwrap().contains("synthetic")); +} +#[tokio::test] +async fn redirects_are_not_followed_even_with_a_credential() { + let destination = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let redirect = format!( + "HTTP/1.1 302 Found\r\nLocation: http://{}/capture\r\nContent-Length: 0\r\n\r\n", + destination.local_addr().unwrap() + ); + let (endpoint, server) = fixture(redirect).await; + assert_eq!( + Transport::new(None) + .unwrap() + .liveness(&endpoint, Some(&Secret::new("synthetic".into()).unwrap())) + .await, + Err(SafeError::Redirect) + ); + server.await.unwrap(); + assert!( + tokio::time::timeout(std::time::Duration::from_millis(100), destination.accept()) + .await + .is_err() + ); +} +#[tokio::test] +async fn projects_errors_without_server_body_or_secrets() { + for (status, error) in [ + ("401 Unauthorized", SafeError::Unauthorized), + ("403 Forbidden", SafeError::Forbidden), + ("503 Unavailable", SafeError::Server), + ] { + let (endpoint, server) = fixture(response(status, "private-body-and-token")).await; + let result = Transport::new(None) + .unwrap() + .liveness(&endpoint, None) + .await + .unwrap_err(); + assert_eq!(result, error); + assert!(!serde_json::to_string(&result).unwrap().contains("private")); + server.await.unwrap(); + } +} +#[tokio::test] +async fn rejects_oversized_and_invalid_responses() { + for body in [ + "x".repeat(MAX_RESPONSE_BYTES + 1), + r#"{"status":"degraded"}"#.into(), + "".into(), + ] { + let (endpoint, server) = fixture(response("200 OK", &body)).await; + let result = Transport::new(None) + .unwrap() + .liveness(&endpoint, None) + .await; + assert!(matches!( + result, + Err(SafeError::ResponseTooLarge | SafeError::InvalidResponse) + )); + // Client may close before the fixture finishes writing an oversized body. + let _ = server.await; + } +} diff --git a/desktop/tsconfig.json b/desktop/tsconfig.json new file mode 100644 index 000000000..a26918d49 --- /dev/null +++ b/desktop/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "allowImportingTsExtensions": true, + "types": [ + "vite/client", + "vitest/globals" + ], + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "include": [ + "ui", + "vite.config.ts" + ] +} diff --git a/desktop/ui/index.html b/desktop/ui/index.html new file mode 100644 index 000000000..861b138ea --- /dev/null +++ b/desktop/ui/index.html @@ -0,0 +1,17 @@ + + +PowerContext Desktop

diff --git a/desktop/ui/src/app/App.tsx b/desktop/ui/src/app/App.tsx new file mode 100644 index 000000000..e026dde81 --- /dev/null +++ b/desktop/ui/src/app/App.tsx @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2026 OceanBase. + * + * 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 + * + * http://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. + */ + +import { useEffect, useRef, useState } from "react"; +import { messages, type Language } from "./messages"; +import { getFoundationInfo } from "../shared/ipc"; +import type { FoundationInfo } from "../generated/ipc"; +import logo from "../../../src-tauri/icons/brand.png"; +import homeIcon from "../assets/overview.svg"; +import connectionsIcon from "../assets/connections.svg"; +import memoryIcon from "../assets/memory.svg"; + +type Page = "home" | "connections" | "memories" | "settings"; +type Theme = "light" | "dark" | "system"; +export function App() { + const [language, setLanguage] = useState("zh"); + const [theme, setTheme] = useState("system"); + const [page, setPage] = useState("home"); + const [menu, setMenu] = useState(false); + const [host, setHost] = useState(null); + const heading = useRef(null); + const t = messages[language]; + useEffect(() => { + getFoundationInfo() + .then(setHost) + .catch(() => setHost(null)); + }, []); + useEffect(() => { + document.documentElement.lang = language === "zh" ? "zh-CN" : "en"; + }, [language]); + useEffect(() => { + document.documentElement.dataset.theme = theme; + }, [theme]); + function navigate(next: Page) { + setPage(next); + setMenu(false); + requestAnimationFrame(() => heading.current?.focus()); + } + const connectButton = ( + + ); + return ( +
+ + {t.skip} + +
+ PowerContext + +
+ +
+
+
+

+ {t[page]} +

+

+ {page === "home" + ? t.tagline + : page === "connections" + ? t.connectionIntro + : page === "memories" + ? t.findHint + : t.foundation} +

+
+ {t.foundation} +
+ {page === "home" && ( + <> +
+
+

{t.quick}

+

{t.noteHint}

+ +