From 520f438a2ca37df2a3b022fefc770b90199c2c7f Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:20:03 +0100 Subject: [PATCH 01/33] docs: plan for a working state the documentation of 2026-11-03 found bugs in nearly every feature: the build fails, the driver pool never lets go of a client, tab views multiply and run queries several times, query errors are swallowed, shell functions silently match nothing. the plan fixes them and completes what querying needs (paging, count, sort, projection), lets several connections be open at once and accepts connection strings with tls, replica set and timeout options. decisions 1 to 4 are the answers given before the plan was written, 5 to 23 were agreed with the go-ahead to build. thirteen steps, one commit each with its tests. --- docs/plans/README.md | 1 + docs/plans/working-state.md | 204 ++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 docs/plans/working-state.md diff --git a/docs/plans/README.md b/docs/plans/README.md index 0484776..6573c7b 100644 --- a/docs/plans/README.md +++ b/docs/plans/README.md @@ -8,6 +8,7 @@ A plan names the GitHub issues it covers. | Plan | What | Status | |---|---|---| +| [working-state.md](working-state.md) | Fix the bugs found on 2026-11-03, complete querying (paging, count, sort, projection), several connections at once, connection strings with options | Agreed 2026-11-03, being built on `fix/working_state` | ## Implemented diff --git a/docs/plans/working-state.md b/docs/plans/working-state.md new file mode 100644 index 0000000..89b82e1 --- /dev/null +++ b/docs/plans/working-state.md @@ -0,0 +1,204 @@ +# Working state: bugs fixed, querying complete, several connections at once + +> **Status:** open, written on 2026-11-03. Decisions 1 to 4 were agreed with Kilian on 2026-11-03, decisions 5 to 23 with the go-ahead to build the same day. Built on `fix/working_state` from `develop`. + +## Context + +Monolens was picked up again on 2026-11-03 after a pause since March. The documentation written that day (`83ee6a3`) lists what `develop` does and what is broken. Kilian's goal for this round: a working state, with queries and everything around them, as the base for developing the tool further. Writing data comes after. + +What is broken or missing today, read from the code. The feature files have the details: + +- **Build**: `pnpm build` and `pnpm tauri build` fail on an unused import in `tokens.test.ts` ([app-shell.md](../features/app-shell.md)). +- **Connections**: + - The Rust pool never drops a driver, so edits and a corrected password need a restart ([connect-and-explorer.md](../features/connect-and-explorer.md)). + - The host field suggests `mongodb+srv://`, but only host and port work ([connection-manager.md](../features/connection-manager.md)). + - `connectionType` is never read, and its TypeScript value `"SharedCluster"` doesn't match Rust's. + - A keyring failure reads as a host problem ([credential-storage.md](../features/credential-storage.md)). +- **Connection test**: a failing stage isn't marked failed, and a user without the `serverStatus` privilege fails although connecting would work ([connection-test.md](../features/connection-test.md)). +- **Tabs and shortcuts** ([tabs.md](../features/tabs.md), [shortcuts.md](../features/shortcuts.md)): + - Every tab's container keys the view by the active tab, so views multiply and run the query several times. + - `Ctrl+Enter` runs in every view (#42). + - `CommandRegistry.unsubscribe` calls the subscriber. + - Tabs survive a switch of connection and then query the new server. +- **Queries** ([query-tab.md](../features/query-tab.md)): + - Errors from the server are swallowed. + - A query can't be cancelled. + - No paging, sort or projection; the total is counted but never shown. + - The autocomplete only knows the first document's fields. + - Several shell functions silently become filters that match nothing (`ISODate("2024-01-01")`, a bad `ObjectId`, `BinData`). +- **Errors and logs**: `FindDocumentsFailed` drops the server's message ([error-handling.md](../features/error-handling.md)). The log level is `Debug` in release builds, and the dialog logs passwords at `trace` ([logging.md](../features/logging.md)). +- **Display**: `Int64` above 2^53 loses precision ([document-views.md](../features/document-views.md)). +- **Dead code** ([overview.md](../architecture/overview.md#commands)): + - wrappers for Rust commands that no longer exist + - an unused repository layer + - two unused synchronous commands + - leftovers of the Vite template + +## Decisions + +| # | Decision | Why | Status | +|---|---|---|---| +| 1 | **Several connections at once.** Each open connection is a node in the sidebar with its databases and collections. Tabs of all open connections sit side by side, and each tab belongs to its connection | Kilian's choice. Working with two servers (e.g. staging and local) is common | agreed | +| 2 | **Querying gets paging, the total count, sort and projection** | Kilian's choice. Issue #12 listed them and was closed without them | agreed | +| 3 | **Connection strings plus options.** A connection is either host and port with option fields (TLS, replica set, timeout), or a `mongodb://` / `mongodb+srv://` connection string | Kilian's choice. Closes issue #4 properly | agreed | +| 4 | **Also in this round:** remove dead code; a connection test that goes on without the `serverStatus` privilege; a dialog of the app instead of `confirm()` for deleting; `Cmd` instead of `Ctrl` on macOS | Kilian's choice | agreed | +| 5 | Commands that talk to MongoDB take a **connection id**, not the connection object. Rust loads the saved connection and its password itself. The connection test keeps taking the form data, because it may not be saved | The UI's copy can be stale after an edit, and the password no longer passes through the web view for these calls. The pool is keyed by id anyway | agreed | +| 6 | **A driver leaves the pool** on disconnect, on update and delete of its connection, and when its first command after creation fails. The next command builds a new one | Fixes "edits need a restart" and "a wrong password sticks" | agreed | +| 7 | **Connection model v2** with `target` (`Host { host, port }` or `Uri { uri }`) and `options`. `connectionType` is dropped. `STORAGE_VERSION` becomes 2; a v1 file is migrated on load and written back. Keyring entries stay as they are (keyed by id) | The topology is expressed by the connection string or the replica set option. `connectionType` was never read | agreed | +| 8 | **URI mode keeps everything but the credentials in the URI.** On save, Rust moves credentials found in the URI out: the username to `authentication.username`, the password to the keyring. The stored URI has no user info. The option fields apply to host mode only | One place for each setting, and no password in `connections.json` | agreed | +| 9 | **The client is built from `ClientOptions`**, not from a URL string. Host mode uses the builder, URI mode `ClientOptions::parse`; then the credential is set | Replaces the string building with `url`, its percent-encoding, and the `mongodb://` prefix that broke SRV | agreed | +| 10 | **Host-mode options:** TLS on/off, CA file, allow invalid certificates, replica set name, server selection timeout in seconds. Empty means the driver's default (30 s) | What issue #4 and decision 3 ask for, without client certificates (X.509 is out of scope) | agreed | +| 11 | **Disconnect closes the tabs of that connection.** `Mod+Shift+D` disconnects the connection of the active tab. Deleting an open connection disconnects it first | With several connections, a tab without its connection has nothing to show | agreed | +| 12 | **Sidebar per connection:** refresh, edit and disconnect on each connection node; collections are cached per connection in the store. The header dropdown opens further connections and has "Add new connection…". Editing an open connection drops its driver and reloads its databases; its tabs stay | Editing must work while connected, and the grid only shows when nothing is open | agreed | +| 13 | **A tab shows the collection, with connection and database as second line.** The view is keyed by its own tab id, gets the tab id as a prop and reads its own context | Fixes the multiplied views and the wrong connection; the label tells two `users` collections apart | agreed | +| 14 | **The count runs next to the find:** `estimated_document_count` for an empty filter, `count_documents` otherwise | Counting a big collection with `countDocuments` scans it. The estimate reads metadata | agreed | +| 15 | **Documents leave Rust as relaxed extended JSON** (dates as ISO strings), except `Int64` beyond ±2^53, which stays `{ "$numberLong": "…" }` | Readable dates in the JSON view, and no silent precision loss | agreed | +| 16 | **Parser fixes and additions:** `ISODate`, `Date` and `new Date` with a date-only or zone-less string become UTC RFC 3339, an invalid date is a parse error; `ObjectId` must be 24 hex characters; `BinData` subtype as hex; `RegExp(…)` and `/re/flags` literals become `$regularExpression`, so they also work inside `$in`; `NumberInt`; `UUID(…)` as binary subtype 4; dotted keys without quotes; numbers with exponents; nothing may follow the value | Shell syntax users type every day, and every case that silently matched nothing becomes an error or works | agreed | +| 17 | **Query errors show the server's message**, e.g. "unknown operator: $foo". `FindDocumentsFailed` carries it | It names the mistake in the query | agreed | +| 18 | **Connection test stages:** Initialize, Ping (also authenticates), Reading status (`serverStatus`, *skipped* without the privilege, the test goes on), Detecting version (`buildInfo`, needs no privilege; the version goes into the title), Connected. A failing stage is marked failed. The driver first emits all stages as pending, so the titles exist only in Rust. Events carry a test id from the UI | Decision 4's lenient stage, plus the bugs of the stepper | agreed | +| 19 | **`DriverError::CredentialsUnavailable`** for keyring failures, with its own message | The message pointed at host and port | agreed | +| 20 | **Log level `Info` in release, `Debug` in debug builds.** The dialog no longer logs form values | Less noise, no password even at `trace` | agreed | +| 21 | **Bindings as `mod+…`:** `Ctrl` on Linux and Windows, `Cmd` on macOS. On macOS Tauri's default menu binds `Cmd+W` to "Close Window"; `lib.rs` builds the default menu without that item on macOS | Decision 4. Without the menu change `Cmd+W` closes the app instead of the tab | agreed | +| 22 | **A `ConfirmDialog` with a `useConfirm()` composable**, built from the existing shadcn `Dialog` | Decision 4; also needed later for deleting data | agreed | +| 23 | **Tests:** vitest with `happy-dom` and Tauri's `mockIPC` for stores and `abortableInvoke`; Rust unit tests with an in-memory credential store behind a `CredentialStore` trait and temp directories; Rust integration tests against a local MongoDB marked `#[ignore]`, run with `cargo test -- --ignored` and `MONGODB_TEST_URI` | The rule "every piece of logic gets unit tests". The keyring and MongoDB can't be in the default test run | agreed | + +## How it works afterwards + +**`connections.json`, version 2** + +```json +{ + "version": 2, + "connections": { + "": { + "id": "", + "name": "Local", + "connector": "MongoDb", + "target": { "kind": "Host", "host": "localhost", "port": 27017 }, + "authentication": { "kind": "BASIC", "username": "root", "password": null, "database": "admin" }, + "options": { + "tls": false, + "tlsCaFile": null, + "tlsAllowInvalidCertificates": false, + "replicaSet": null, + "serverSelectionTimeoutSecs": null + } + } + } +} +``` + +A connection string looks like `"target": { "kind": "Uri", "uri": "mongodb+srv://cluster0.example.net/?retryWrites=true" }`, and its `options` are ignored. The v1 → v2 migration turns `uri` and `port` into a `Host` target, drops `connectionType` and sets default options. + +**Commands** + +| Command | Change | +|---|---| +| `start_test_connection(connection, testId)` | Takes the form data as before, plus the test id the events echo | +| `start_connect(connectionId)` | By id; drops the driver again if listing the databases fails | +| `disconnect(connectionId)` | New: drops the pooled driver | +| `list_collections(connectionId, databaseName)` | By id, loads the password | +| `start_find_documents(connectionId, databaseName, collectionName, filter, sort, projection, skip, limit)` | Sort and projection added; the count runs alongside | +| `update_connection`, `delete_connection` | Also drop the pooled driver | +| `test_connection`, `get_databases`, `get_connection` | Removed (unused) | + +**UI** + +``` ++--------------------------------------------------------------+ +| [logo] | Connections v | ++------------------+-------------------------------------------+ +| EXPLORER | users orders users | +| v Local ⟳ ✎ ⏏ | Local·shop Local·shop Staging·crm | +| v shop +-------------------------------------------+ +| users | Filter [{ age: { $gt: 18 } } ] ▶ | +| orders | Sort [{ createdAt: -1 }] Projection [] | +| > Staging ⟳ ✎ ⏏ | 51–100 of 1,234 ‹ › Limit 50 ▦ {} | ++------------------+-------------------------------------------+ +``` + +The grid shows only while no connection is open. + +## Steps + +Every step is one commit with its tests. They run in this order, because later steps use the earlier ones. + +1. **Build**: remove the unused import in `tokens.test.ts`. The test named "throws" gets a name and an assertion. +2. **Shortcuts**: + - `unsubscribe` uses `indexOf`. + - `eventToKeyString` emits `mod`, and the bindings become `mod+w`, `mod+shift+d`, `mod+enter`. + - On macOS, `lib.rs` builds Tauri's default menu without "Close Window". + - Tests for the registry and the key strings. +3. **Query parser**: decision 16, with tests per case. +4. **Rust: credential store and model v2**: + - `CredentialStore` trait with the keyring implementation and an in-memory one for tests. + - `ConnectionTarget`, `ConnectionOptions`. + - `STORAGE_VERSION` 2 with the v1 migration in `FileRepository.load_storage`. + - Moving credentials out of URIs on create and update. + - Tests for migration, save, update, delete and credential moving, with temp directories. +5. **Rust: client options**: build `ClientOptions` from host mode or a URI, set the credential and TLS options (decisions 9 and 10). Unit tests for the options built. +6. **Rust: commands by id and the pool**: + - Decisions 5 and 6. + - `disconnect`. + - `hydrate` everywhere. + - `CredentialsUnavailable`. + - The log level. + - Removing `test_connection`, `get_databases` and `get_connection`. + - Unit tests for pool invalidation (with a fake driver from the factory) and `DriverError::user_message`. + - Integration tests marked `#[ignore]`. +7. **Connection test**: decision 18 in the driver and the command; the store builds its stages from the events; `TestStagesDisplay` shows skipped and failed stages. +8. **Rust: find**: sort, projection, the count strategy, relaxed extended JSON (decisions 14, 15, 17). Integration tests. +9. **UI: connections**: + - TypeScript models v2. + - `ConnectionDialog` with a mode switch (host and port with options, or connection string) and credentials in both modes. + - `ConfirmDialog` and `useConfirm` for deleting. + - The dialog's password logs removed. +10. **UI: several connections**: + - `connectionStore` with open sessions per connection (status, databases, collections, abort controller). + - The sidebar with one node per connection. + - The header dropdown. + - Tabs with `{ connectionId, database, collection }`, keyed by their own id, closed on disconnect. + - `mod+enter` only in the active tab. + - Store tests with `mockIPC`. +11. **UI: query tab**: + - Through `ConnectionServiceIPC.findDocuments` with cancel. + - Error toasts. + - Sort and projection inputs. + - Paging with "x–y of N". + - The page resets when filter, sort, projection or limit change. + - Autocomplete from all documents. +12. **Cleanup**: + - `ConnectionRepository(IPC)` and the `save_connection(s)` wrappers. + - The double load of the connections. + - The guard in the JSON view's watcher. + - Template leftovers: favicon, title, `vite.svg`, `tauri.svg`, `vue.svg`. +13. **Docs**: + - Update the feature files (building steps, "How it works", limits), `overview.md`, `decisions.md`, `CLAUDE.md` (gotchas that are gone) and the root README feature list. + - This plan gets its status note and moves to `implemented/`. + +## Verification + +- Automated, after every step: `pnpm test:frontend --run`, `pnpm build`, `cargo test`, `cargo clippy`. +- From step 6 on, also `cargo test -- --ignored` against `docker run --rm -p 27017:27017 mongo:8`. +- Manually in `pnpm tauri dev` against local containers: + - without authentication + - with authentication: root, plus a user with only `readWrite` on one database for the lenient stage + - a one-node replica set (`--replSet rs0`, `rs.initiate()`) in host mode with the replica set name + - TLS with a self-signed certificate, once with the CA file and once with "allow invalid certificates" + - two connections at once, tabs of both, disconnecting one + - paging, sort, projection, a broken query (toast), cancelling a slow query + - editing an open connection (new password takes effect without restart), deleting an open connection +- Migration: back up `~/.config/org.monolens/connections.json` (three v1 connections), start the new build, check the file is v2 and the connections still connect. +- Can't be verified here: + - `mongodb+srv://`, which needs DNS SRV records, e.g. an Atlas cluster, if Kilian has one. + - `Cmd` and the menu, which need a Mac. + +## Out of scope + +- Writing data (#5, #6, #7, #9, #43) and nested objects on double click (#39). +- Saving column widths. +- A CSP, i18n (#31), log file rotation (#18). +- Query builder (#11, #41), export as code (#13). +- Stage types (#45), quick connections (#40), database statistics (#14), in-memory MongoDB (#28). +- Authentication other than username and password, and client certificates. +- CI. From c25ace49ce0d20679cc8f7737073b746689c9f19 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:20:19 +0100 Subject: [PATCH 02/33] fix: build fails on an unused import in a test vue-tsc type-checks the tests with noUnusedLocals, so the unused import of T in tokens.test.ts stopped pnpm build and with it pnpm tauri build. the test called "throws" parsed a trailing comma without asserting anything; it now says what it checks. --- src/utils/queryParser/test/query-parser.test.ts | 4 ++-- src/utils/queryParser/test/tokens.test.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/utils/queryParser/test/query-parser.test.ts b/src/utils/queryParser/test/query-parser.test.ts index 78894db..c46badb 100644 --- a/src/utils/queryParser/test/query-parser.test.ts +++ b/src/utils/queryParser/test/query-parser.test.ts @@ -89,7 +89,7 @@ describe('parseMongoQuery — error handling', () => { expect(() => parseMongoDbQuery('{ a 1 }')).toThrow() }) - it('throws', () => { - parseMongoDbQuery('{ a: 1, }') + it('accepts a trailing comma', () => { + expect(parseMongoDbQuery('{ a: 1, }')).toEqual({ a: 1 }) }) }) \ No newline at end of file diff --git a/src/utils/queryParser/test/tokens.test.ts b/src/utils/queryParser/test/tokens.test.ts index 41e59cd..07452e3 100644 --- a/src/utils/queryParser/test/tokens.test.ts +++ b/src/utils/queryParser/test/tokens.test.ts @@ -1,6 +1,5 @@ import { test, expect, it } from "vitest"; import { generateTokens } from "../generateTokens"; -import { T } from "../types"; test("Test Tokens generation", () => { const tokens = generateTokens(`{name: "test", age: 16}`); From e19ec32553ffbde5c0369bdbcc5514cb34ed2561 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:32:07 +0100 Subject: [PATCH 03/33] chore: pin pnpm 12 node_modules was installed with pnpm 10 while the machines run newer versions, so every pnpm command wanted a fresh install from another store. pnpm is now pinned in packageManager (corepack) and devEngines.packageManager (pnpm itself, which switches to the version and records it in the lockfile), the same way as in smtp-relay. pnpm 12 refuses to install while build scripts are not approved; pnpm-workspace.yaml allows the two this project has: esbuild and vue-demi. --- CLAUDE.md | 3 +- package.json | 10 ++- pnpm-lock.yaml | 183 ++++++++++++++++++++++++++++++++++++++++++++ pnpm-workspace.yaml | 3 + 4 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 pnpm-workspace.yaml diff --git a/CLAUDE.md b/CLAUDE.md index edf1068..ede1a6b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ Read `docs/README.md` first. `docs/architecture/overview.md` has every IPC comma ## Repository -Single package, always use pnpm (lockfile v9). The Rust crate lives in `src-tauri`. +Single package, always use pnpm. It is pinned in `package.json` (`packageManager` and `devEngines.packageManager`, 12.17.0); a plain `pnpm` switches to that version. Build scripts of dependencies only run when `pnpm-workspace.yaml` lists them under `allowBuilds`, else `pnpm install` fails. The Rust crate lives in `src-tauri`. | Path | Content | |---|---| @@ -104,6 +104,7 @@ Needs Rust and the Tauri prerequisites (`README.md`). For a manual check run a l - The log level is `Debug` in release builds too. `ConnectionDialog` logs form values, password included, at `trace`. - Query filters cross IPC as extended JSON. bson turns `{ $oid }`, `{ $date: "" }` and the number wrappers into BSON types; anything it can't read stays a plain object and silently matches nothing. - On Linux the keyring needs a Secret Service (GNOME Keyring, KWallet). `keyring` is built with `vendored`, which compiles OpenSSL. +- Change the pinned pnpm with `pnpm self-update ` inside the repo, never by hand, or `--frozen-lockfile` fails (pnpm records its version in the lockfile). - `gh` is not installed on this machine. The repo is public: read issues and pull requests through `https://api.github.com/repos/WebXIO/monolens/issues` and `/pulls`. ## graphify diff --git a/package.json b/package.json index a9387fc..0af00cf 100644 --- a/package.json +++ b/package.json @@ -45,5 +45,13 @@ "vite": "^6.4.1", "vitest": "^4.0.18", "vue-tsc": "^2.2.12" - } + }, + "devEngines": { + "packageManager": { + "name": "pnpm", + "version": "12.17.0", + "onFail": "download" + } + }, + "packageManager": "pnpm@12.17.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f93224..11f174e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,186 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + '@pnpm/exe': + specifier: 12.17.0 + version: 12.17.0 + pnpm: + specifier: 12.17.0 + version: 12.17.0 + +packages: + + '@pnpm/exe.android-arm64@12.17.0': + resolution: {integrity: sha512-gwu/F5YyoJp1bIbrIBl7B8JO3rkjkGlKikwQg9s0aVa5xWaBYIqPX+ZJqQ7I4D1YfbdI/Omfze0+6vnYiWHG6A==} + cpu: [arm64] + os: [android] + + '@pnpm/exe.android-x64@12.17.0': + resolution: {integrity: sha512-qUNhCvWyeBrUByNWkqqQ3Koy1gIAQ8UV5HDHXxoo5NUWVTde0Ld2BxweNwWJw8CNKpqEGceCUdjZ506JYpTjJg==} + cpu: [x64] + os: [android] + + '@pnpm/exe.darwin-arm64@12.17.0': + resolution: {integrity: sha512-0nkEqRLIbrm7dWl+p2EPpmyNKyM0bbdPEovdtMhHYbhkO+Vls38S+6emkx8kSTAr75BNXYXkCl4RtGinGG4Erg==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.17.0': + resolution: {integrity: sha512-w89cboNi4KCzmt/dSKrE4ijVNKICKiZsE9TcIWf77Tz+VpoDfuhPSmWPZK+iCHBvlI/9dIN+M3HiPPVsFnAx4Q==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.freebsd-x64@12.17.0': + resolution: {integrity: sha512-DJ0FOaUDXc71icSgiuBFEvqReqoSiS/rmnC6kltoiC3MzPyw3awcGbT/7FnnYzi/ziuoTC7v6vfBh0Vzv7VKOQ==} + cpu: [x64] + os: [freebsd] + + '@pnpm/exe.linux-arm64-musl@12.17.0': + resolution: {integrity: sha512-w5ZwZ4j8S804DGhMYlLLpc+G3Kkc+5GlDO++LLvO/nDIXBTHRhdxPfQBQU08q31k0JYfp3wXCQk0Y7DnsuVF6w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.17.0': + resolution: {integrity: sha512-Cj2nIzWTVm6ZuhQHqL9SiJ11scBnEGxJyNg7tYQPzh9fVF5UVRkv+LbyfwdftnAtJerK/7HDpK/55WeQqp8OkA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-ppc64@12.17.0': + resolution: {integrity: sha512-Gb//Wm15fXl+qWcxjNQmwlYDjGiJOnLU/A9uRZYmtkyZie2Yx8AHI6XkUIJioQz99TwVDKQ87ywD5Jtk8zcgyg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-riscv64@12.17.0': + resolution: {integrity: sha512-+kItEcFjdVZEDzODsc7icb8cB+3AouCrEzOCezzxLITRhw86m9t3J/qyPdcFELBjeMnS+IXV8sJaSCQcpSqfgA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-s390x@12.17.0': + resolution: {integrity: sha512-jf5ghD2uDeknWQgK/EsCFNwlyL7BYLWfXe687g5UMVFclPLt524CREZ8Yl5hf4u7p3evCIPBN/m5I1QXUmJpHw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.17.0': + resolution: {integrity: sha512-JGxrGSxkDkqRAUD49T9dOnKyJkQ3bWBeHnYH4o4mvj09R9eUzhWFi8oa6WPNyCO0/7/Max2gsSfgXOHj3QW7ug==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.17.0': + resolution: {integrity: sha512-vQAusDzMofc/Ee4KOUYjE6FWeHOlMGQyvhR7W39QSamVeJWS16co/n+bhjdjwjI3UFh8IWOpamvTS+b4lvQUog==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.17.0': + resolution: {integrity: sha512-qDQh8rmyK5sxlaCSCADcmPrvytJabMCbxtJ0nCitzRo2j3/8BhzLjlOcWF3C6iPGhR5CbIb+btNy+VCVhd06mQ==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.17.0': + resolution: {integrity: sha512-qCo1OQlE3WrFZIAUK0O5EoupLaQ1fST7zNX8Qd+Tc4ojWgCvYA/ze0uP9hox8mSFC/JPAGRSG5o8gUBSq2rRxw==} + cpu: [x64] + os: [win32] + + '@pnpm/exe@12.17.0': + resolution: {integrity: sha512-Qmg3mFIQi/v0oa2OOosQlwEgJ+5av4KnUojIncC/Sb3ykw13iSm95USdLocH6T6j7ytxUsyLO9IU3mXHyMOsWg==} + engines: {node: '>=18'} + hasBin: true + + pnpm@12.17.0: + resolution: {integrity: sha512-uNIj6+wEtYContIG2qcdG8y2oe4dUu+pXMOw23UnFWHfjw2OLEOt05xewIAYr3qKlRCOcJD5Win4hye3pA/VPQ==} + engines: {node: '>=18'} + hasBin: true + +snapshots: + + '@pnpm/exe.android-arm64@12.17.0': + optional: true + + '@pnpm/exe.android-x64@12.17.0': + optional: true + + '@pnpm/exe.darwin-arm64@12.17.0': + optional: true + + '@pnpm/exe.darwin-x64@12.17.0': + optional: true + + '@pnpm/exe.freebsd-x64@12.17.0': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.17.0': + optional: true + + '@pnpm/exe.linux-arm64@12.17.0': + optional: true + + '@pnpm/exe.linux-ppc64@12.17.0': + optional: true + + '@pnpm/exe.linux-riscv64@12.17.0': + optional: true + + '@pnpm/exe.linux-s390x@12.17.0': + optional: true + + '@pnpm/exe.linux-x64-musl@12.17.0': + optional: true + + '@pnpm/exe.linux-x64@12.17.0': + optional: true + + '@pnpm/exe.win32-arm64@12.17.0': + optional: true + + '@pnpm/exe.win32-x64@12.17.0': + optional: true + + '@pnpm/exe@12.17.0': + optionalDependencies: + '@pnpm/exe.android-arm64': 12.17.0 + '@pnpm/exe.android-x64': 12.17.0 + '@pnpm/exe.darwin-arm64': 12.17.0 + '@pnpm/exe.darwin-x64': 12.17.0 + '@pnpm/exe.freebsd-x64': 12.17.0 + '@pnpm/exe.linux-arm64': 12.17.0 + '@pnpm/exe.linux-arm64-musl': 12.17.0 + '@pnpm/exe.linux-ppc64': 12.17.0 + '@pnpm/exe.linux-riscv64': 12.17.0 + '@pnpm/exe.linux-s390x': 12.17.0 + '@pnpm/exe.linux-x64': 12.17.0 + '@pnpm/exe.linux-x64-musl': 12.17.0 + '@pnpm/exe.win32-arm64': 12.17.0 + '@pnpm/exe.win32-x64': 12.17.0 + + pnpm@12.17.0: + optionalDependencies: + '@pnpm/exe.android-arm64': 12.17.0 + '@pnpm/exe.android-x64': 12.17.0 + '@pnpm/exe.darwin-arm64': 12.17.0 + '@pnpm/exe.darwin-x64': 12.17.0 + '@pnpm/exe.freebsd-x64': 12.17.0 + '@pnpm/exe.linux-arm64': 12.17.0 + '@pnpm/exe.linux-arm64-musl': 12.17.0 + '@pnpm/exe.linux-ppc64': 12.17.0 + '@pnpm/exe.linux-riscv64': 12.17.0 + '@pnpm/exe.linux-s390x': 12.17.0 + '@pnpm/exe.linux-x64': 12.17.0 + '@pnpm/exe.linux-x64-musl': 12.17.0 + '@pnpm/exe.win32-arm64': 12.17.0 + '@pnpm/exe.win32-x64': 12.17.0 + +--- lockfileVersion: '9.0' settings: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..a23eae0 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + esbuild: true + vue-demi: true From 3493da81d893112b98f042852f8ed0ca627daea0 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:35:57 +0100 Subject: [PATCH 04/33] chore: update npm packages every package to its latest release, with three exceptions decided with the update: typescript stays on 6.0 because vue-tsc can't run on typescript 7 (it no longer ships lib/tsc); zod and vee-validate follow in their own commit, because @vee-validate/zod only supports zod 3. lucide-vue-next is deprecated and replaced by @lucide/vue, same icon names. typescript 6 deprecates baseUrl; paths resolve relative to the tsconfig without it. tanstack table 9 only exposes the apis of registered features, so the document table now declares them (sorting, ordering, visibility, sizing, resizing, the sorted row model and the sort functions 'auto' picks from) and uses useTable, sortFn and the FlexRender shorthand. tests for the table check columns, sorting, the saved column order and replaced data against the new api; vitest now runs in happy-dom for them. vue-tsc 3 misread the '//' in the host field's placeholder "localhost or mongodb+srv://..." and reported errors further down the template. the hint was wrong anyway, srv strings don't work yet. checked: tests, pnpm build, the start screen renders in the browser. --- CLAUDE.md | 7 +- docs/architecture/overview.md | 6 +- package.json | 45 +- pnpm-lock.yaml | 2318 ++++++++--------- src/components/AppSidebar.vue | 2 +- src/components/Logo.vue | 2 +- .../connection/ConnectionDialog.vue | 4 +- src/components/connection/ConnectionGrid.vue | 2 +- .../connection/ConnectionSelector.vue | 2 +- .../connection/TestStagesDisplay.vue | 2 +- .../documents/json/JSONDocumentsEditor.vue | 2 +- .../documents/table/TableDocumentsView.vue | 4 +- src/components/query/QueryInput.vue | 2 +- src/components/tabs/TabsContainer.vue | 2 +- src/components/tabs/views/TabViewQuery.vue | 2 +- src/components/ui/dialog/DialogContent.vue | 2 +- .../ui/dialog/DialogScrollContent.vue | 2 +- .../DropdownMenuCheckboxItem.vue | 2 +- .../dropdown-menu/DropdownMenuRadioItem.vue | 2 +- .../dropdown-menu/DropdownMenuSubTrigger.vue | 2 +- .../ui/number-field/NumberFieldDecrement.vue | 2 +- .../ui/number-field/NumberFieldIncrement.vue | 2 +- src/components/ui/sheet/SheetContent.vue | 2 +- src/components/ui/sidebar/SidebarTrigger.vue | 2 +- .../table/test/useDocumentTable.test.ts | 106 + src/composables/table/useColumnDragDrop.ts | 4 +- src/composables/table/useDocumentTable.ts | 93 +- tsconfig.json | 1 - vite.config.ts | 5 + 29 files changed, 1291 insertions(+), 1338 deletions(-) create mode 100644 src/composables/table/test/useDocumentTable.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index ede1a6b..4a0ac7a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,7 +69,7 @@ Needs Rust and the Tauri prerequisites (`README.md`). For a manual check run a l ## Testing - Every piece of logic gets unit tests, for the regular cases and every edge case you can think of: empty and missing input, boundaries, wrong kinds of values, failing collaborators (MongoDB, keyring, file system). -- Frontend: vitest, files `*.test.ts` in a `test/` folder next to the code (as `src/utils/queryParser/test/`). Pull logic out of components into composables or `utils` so it can be tested without mounting. +- Frontend: vitest in happy-dom (the `test` block of `vite.config.ts`), files `*.test.ts` in a `test/` folder next to the code (as `src/utils/queryParser/test/`, `src/composables/table/test/`). Pull logic out of components into composables or `utils` so it can be tested without mounting. - Rust: `#[cfg(test)] mod tests` in the file, `cargo test`. Abstract MongoDB and the keyring behind traits where a test needs to replace them. - Untested today, worth covering when touched: `formatCellValue`, `mergeColumnOrder` and the column sizing, `eventToKeyString` and `CommandRegistry`, `tabsStore`, `extractErrorMessage`, `abortableInvoke`; in Rust `TaskManager`, `DriverError::user_message`, `build_connection_string`, `FileRepository`. - `vue-tsc` type-checks the test files with `noUnusedLocals`, so an unused import in a test breaks `pnpm build`. @@ -93,7 +93,10 @@ Needs Rust and the Tauri prerequisites (`README.md`). For a manual check run a l ## Gotchas -- `pnpm build` (and `pnpm tauri build`) fails on `develop` as of 2026-11-03: `'T' is declared but its value is never read` in `src/utils/queryParser/test/tokens.test.ts`. +- TypeScript stays on 6.x: `vue-tsc` can't run on TypeScript 7, which no longer ships `lib/tsc`. TypeScript 6 deprecates `baseUrl`, so the tsconfig has `paths` only. +- Run tools with `pnpm exec`, not `npx`: npm refuses to run in this repo, because `devEngines` names pnpm. +- TanStack Table 9 only has the APIs of registered features. The table's features are `documentTableFeatures` in `useDocumentTable.ts`; `row.getVisibleCells()`, for example, needs `columnVisibilityFeature`. +- vue-tsc 3 breaks on a `//` inside a static attribute value (a placeholder like `mongodb+srv://...` made it report errors further down the template). - The driver pool never drops a driver. After a failed connect or an edited connection, the old MongoDB client stays until restart. Disconnect in the UI only resets frontend state. - `TabsContainer` keys each tab's view by the *active* tab id, so views multiply and run duplicate queries. `Ctrl+Enter` runs in every mounted view (issue #42), and `CommandRegistry.unsubscribe` uses `findIndex(subscriber)`, which calls the subscriber. Details in `docs/features/tabs.md` and `shortcuts.md`. - `TabViewQuery` queries `connectionStore.activeConnection`, not the tab's own connection, and tabs survive a switch of connection. diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index c0dd7f4..312a7bd 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -32,10 +32,10 @@ This file describes `develop` as of 2026-11-03 (`859c252`). `main` is at `efee3a | Part | Technology | Path | |---|---|---| | Rust core | Tauri 2.10, tokio, `mongodb` 3.5 (bson 2.15), `keyring` 3.6, `thiserror`, `tauri-plugin-log`, `tauri-plugin-opener` | `src-tauri/src` | -| UI | Vue 3.5, Pinia 3, Tailwind 4 with shadcn-vue components on reka-ui, vee-validate + zod, vue-sonner, lucide icons | `src` | +| UI | Vue 3.5, Pinia 4, Tailwind 4 with shadcn-vue components on reka-ui, vee-validate + zod, vue-sonner, lucide icons (`@lucide/vue`) | `src` | | Query editor and JSON view | CodeMirror 6 (`@codemirror/lang-json`, `theme-one-dark`, `autocomplete`) | `src/components/query`, `src/components/documents/json` | -| Table view | TanStack Table 8 and TanStack Virtual 3 | `src/components/documents/table`, `src/composables/table` | -| Frontend tests | vitest 4 | `src/utils/queryParser/test` | +| Table view | TanStack Table 9 and TanStack Virtual 3 | `src/components/documents/table`, `src/composables/table` | +| Frontend tests | vitest 5 in happy-dom | `test/` folders next to the code | | Generated UI kit | shadcn-vue (`components.json`, style `new-york`) | `src/components/ui` | The app is one window of 1200 × 900 (`src-tauri/tauri.conf.json`), identifier `org.monolens`. In development Vite serves the UI on port 1420 and `pnpm tauri dev` loads it. diff --git a/package.json b/package.json index 0af00cf..389fbc2 100644 --- a/package.json +++ b/package.json @@ -11,40 +11,41 @@ "test:frontend": "vitest" }, "dependencies": { - "@codemirror/autocomplete": "^6.20.1", + "@codemirror/autocomplete": "^6.20.4", "@codemirror/lang-json": "^6.0.2", "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.39.16", - "@tailwindcss/vite": "^4.2.1", - "@tanstack/vue-table": "^8.21.3", - "@tanstack/vue-virtual": "^3.13.21", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-log": "~2.8.0", - "@tauri-apps/plugin-opener": "^2.5.3", + "@codemirror/view": "^6.43.15", + "@lucide/vue": "^1.66.0", + "@tailwindcss/vite": "^4.3.3", + "@tanstack/vue-table": "^9.3.1", + "@tanstack/vue-virtual": "^3.13.51", + "@tauri-apps/api": "^2.12.4", + "@tauri-apps/plugin-log": "~2.10.1", + "@tauri-apps/plugin-opener": "^2.7.2", "@vee-validate/zod": "^4.15.1", - "@vueuse/core": "^14.2.1", + "@vueuse/core": "^15.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "codemirror": "^6.0.2", - "lucide-vue-next": "^0.563.0", - "pinia": "^3.0.4", - "reka-ui": "^2.8.2", - "tailwind-merge": "^3.5.0", - "tailwindcss": "^4.2.1", + "pinia": "^4.1.0", + "reka-ui": "^2.11.0", + "tailwind-merge": "^3.7.0", + "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "vee-validate": "^4.15.1", - "vue": "^3.5.29", + "vue": "^3.5.44", "vue-sonner": "^2.0.9", "zod": "3.25.76" }, "devDependencies": { - "@tauri-apps/cli": "^2.10.0", - "@types/node": "^25.3.3", - "@vitejs/plugin-vue": "^5.2.4", - "typescript": "~5.6.3", - "vite": "^6.4.1", - "vitest": "^4.0.18", - "vue-tsc": "^2.2.12" + "@tauri-apps/cli": "^2.12.4", + "@types/node": "^26.6.6", + "@vitejs/plugin-vue": "^6.0.10", + "happy-dom": "^21.0.4", + "typescript": "~6.0.3", + "vite": "^8.3.5", + "vitest": "^5.0.5", + "vue-tsc": "^3.3.14" }, "devEngines": { "packageManager": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11f174e..f46d73b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,8 +192,8 @@ importers: .: dependencies: '@codemirror/autocomplete': - specifier: ^6.20.1 - version: 6.20.1 + specifier: ^6.20.4 + version: 6.20.4 '@codemirror/lang-json': specifier: ^6.0.2 version: 6.0.2 @@ -201,32 +201,35 @@ importers: specifier: ^6.1.3 version: 6.1.3 '@codemirror/view': - specifier: ^6.39.16 - version: 6.39.16 + specifier: ^6.43.15 + version: 6.43.15 + '@lucide/vue': + specifier: ^1.66.0 + version: 1.66.0(vue@3.5.44(typescript@6.0.3)) '@tailwindcss/vite': - specifier: ^4.2.1 - version: 4.2.1(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)) + specifier: ^4.3.3 + version: 4.3.3(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0)) '@tanstack/vue-table': - specifier: ^8.21.3 - version: 8.21.3(vue@3.5.29(typescript@5.6.3)) + specifier: ^9.3.1 + version: 9.3.1(vue@3.5.44(typescript@6.0.3)) '@tanstack/vue-virtual': - specifier: ^3.13.21 - version: 3.13.21(vue@3.5.29(typescript@5.6.3)) + specifier: ^3.13.51 + version: 3.13.51(vue@3.5.44(typescript@6.0.3)) '@tauri-apps/api': - specifier: ^2.10.1 - version: 2.10.1 + specifier: ^2.12.4 + version: 2.12.4 '@tauri-apps/plugin-log': - specifier: ~2.8.0 - version: 2.8.0 + specifier: ~2.10.1 + version: 2.10.1 '@tauri-apps/plugin-opener': - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.7.2 + version: 2.7.2 '@vee-validate/zod': specifier: ^4.15.1 - version: 4.15.1(vue@3.5.29(typescript@5.6.3))(zod@3.25.76) + version: 4.15.1(vue@3.5.44(typescript@6.0.3))(zod@3.25.76) '@vueuse/core': - specifier: ^14.2.1 - version: 14.2.1(vue@3.5.29(typescript@5.6.3)) + specifier: ^15.0.0 + version: 15.0.0(vue@3.5.44(typescript@6.0.3)) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -236,30 +239,27 @@ importers: codemirror: specifier: ^6.0.2 version: 6.0.2 - lucide-vue-next: - specifier: ^0.563.0 - version: 0.563.0(vue@3.5.29(typescript@5.6.3)) pinia: - specifier: ^3.0.4 - version: 3.0.4(typescript@5.6.3)(vue@3.5.29(typescript@5.6.3)) + specifier: ^4.1.0 + version: 4.1.0(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.44(typescript@6.0.3)) reka-ui: - specifier: ^2.8.2 - version: 2.8.2(vue@3.5.29(typescript@5.6.3)) + specifier: ^2.11.0 + version: 2.11.0(vue@3.5.44(typescript@6.0.3)) tailwind-merge: - specifier: ^3.5.0 - version: 3.5.0 + specifier: ^3.7.0 + version: 3.7.0 tailwindcss: - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.3.3 + version: 4.3.3 tw-animate-css: specifier: ^1.4.0 version: 1.4.0 vee-validate: specifier: ^4.15.1 - version: 4.15.1(vue@3.5.29(typescript@5.6.3)) + version: 4.15.1(vue@3.5.44(typescript@6.0.3)) vue: - specifier: ^3.5.29 - version: 3.5.29(typescript@5.6.3) + specifier: ^3.5.44 + version: 3.5.44(typescript@6.0.3) vue-sonner: specifier: ^2.0.9 version: 2.0.9 @@ -268,246 +268,98 @@ importers: version: 3.25.76 devDependencies: '@tauri-apps/cli': - specifier: ^2.10.0 - version: 2.10.0 + specifier: ^2.12.4 + version: 2.12.4 '@types/node': - specifier: ^25.3.3 - version: 25.3.3 + specifier: ^26.6.6 + version: 26.6.6 '@vitejs/plugin-vue': - specifier: ^5.2.4 - version: 5.2.4(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1))(vue@3.5.29(typescript@5.6.3)) + specifier: ^6.0.10 + version: 6.0.10(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0))(vue@3.5.44(typescript@6.0.3)) + happy-dom: + specifier: ^21.0.4 + version: 21.0.4 typescript: - specifier: ~5.6.3 - version: 5.6.3 + specifier: ~6.0.3 + version: 6.0.3 vite: - specifier: ^6.4.1 - version: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) + specifier: ^8.3.5 + version: 8.3.5(@types/node@26.6.6)(jiti@2.7.0) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) + specifier: ^5.0.5 + version: 5.0.5(@types/node@26.6.6)(happy-dom@21.0.4)(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0)) vue-tsc: - specifier: ^2.2.12 - version: 2.2.12(typescript@5.6.3) + specifier: ^3.3.14 + version: 3.3.14(typescript@6.0.3) packages: - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.11': + resolution: {integrity: sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.12': + resolution: {integrity: sha512-WJ7JBp/Q4+z/ImydtI7jS6NVco5++632ExBemSX+Ysb+G1lCwQ5BVo3SY+jGGOcZXI4ZccbZSUSJLNBW6eEpJg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.11': + resolution: {integrity: sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==} engines: {node: '>=6.9.0'} - '@codemirror/autocomplete@6.20.1': - resolution: {integrity: sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==} + '@codemirror/autocomplete@6.20.4': + resolution: {integrity: sha512-yF8RhOf2SXlg00+qtupzLhrglcas61boqaONiNcbPIebHCpJocpqTBA6dyrtUrQO47hqyTdeob/3XnYilT7TaQ==} - '@codemirror/commands@6.10.2': - resolution: {integrity: sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==} + '@codemirror/commands@6.11.1': + resolution: {integrity: sha512-O/4hG3SC1YwcmQ0d2UVNDs+AsaNWd1iHVxbTeEBuqH+6bExAiPK3iS/BvpY6rZGURALv4ZD3sIgcCmRvw3ehBg==} '@codemirror/lang-json@6.0.2': resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} - '@codemirror/language@6.12.2': - resolution: {integrity: sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==} + '@codemirror/language@6.13.1': + resolution: {integrity: sha512-zfvU2r3TyylQLMj/te+5CnQ0rSqZi8B1oTCBbQkagcLW4Xc6imab6qN+pEJhsuNOLaJqiRyBXp9UhWA1DhVvDw==} + + '@codemirror/lint@6.9.7': + resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} - '@codemirror/lint@6.9.5': - resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} + '@codemirror/search@6.7.2': + resolution: {integrity: sha512-gUYkYhT2+n/+VGZ+8EzE5WFkYZUZYm1VOKDudIsNqh42uRVQJ0a6Yss9sdKT3MeOYfuL1N6AZA57oza0Oyr0LA==} - '@codemirror/search@6.6.0': - resolution: {integrity: sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==} + '@codemirror/state@6.7.6': + resolution: {integrity: sha512-kAz+AncRtKuIknedxT1bq4XwXv4UowhbkHU1myPrtVb/jZtImWuV5BXzv5vK6i3kYACsdiZiQKFQQ5Mq7elW8w==} - '@codemirror/state@6.5.4': - resolution: {integrity: sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==} + '@codemirror/streamparser@6.0.0': + resolution: {integrity: sha512-JTFPF6xrfjt0mnfGPgzcLiMwYmvIyNaoizp8BYzv8FE8KrT6GBGDZ190rtt+O7Wke3gG/MFHyiY9YGNeimof4w==} '@codemirror/theme-one-dark@6.1.3': resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} - '@codemirror/view@6.39.16': - resolution: {integrity: sha512-m6S22fFpKtOWhq8HuhzsI1WzUP/hB9THbDj0Tl5KX4gbO6Y91hwBl7Yky33NdvB6IffuRFiBxf1R8kJMyXmA4Q==} - - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] + '@codemirror/view@6.43.15': + resolution: {integrity: sha512-HHsfpqFeHyXLs983pSRe38Xajs0vFWZQ2BuX0m7Ki8w3jZ5iD8cuR3lBz2/5/X53Dhf32SBHKh6rtSTB6tKeGw==} - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@floating-ui/core@1.7.4': - resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} - - '@floating-ui/dom@1.7.5': - resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} - - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - - '@floating-ui/vue@1.1.10': - resolution: {integrity: sha512-vdf8f6rHnFPPLRsmL4p12wYl+Ux4mOJOkjzKEMYVnwdf7UFdvBtHlLvQyx8iKG5vhPRbDRgZxdtpmyigDPjzYg==} + '@floating-ui/vue@2.0.1': + resolution: {integrity: sha512-043dyEKD9TDSfz080YH2vobubgg+NIo/9Fw4RAl7sEMpD8Am1DNrrSTl/GpMBjyGHoD/FbJY2QLawY+HSQsEIA==} + peerDependencies: + vue: '>=3.3.0' - '@internationalized/date@3.11.0': - resolution: {integrity: sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q==} + '@internationalized/date@3.12.4': + resolution: {integrity: sha512-M1dEn4c1U1HsSlaVR8upZtSqvXrTkHDfv18H01uCSJyjVLDxnBR38v/fMxecmlwXKR4i9HeZcmgQAPE6A+aGJQ==} - '@internationalized/number@3.6.5': - resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + '@internationalized/number@3.6.9': + resolution: {integrity: sha512-GgWy2caO/+hV9sT/oCTWGHvbjmJMPT9kkXzoKRLnkEq7adghhR7UprhvY9sXrKfrp3NcDfhF6QQHXR1KfQbB8g==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -519,234 +371,200 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@lezer/common@1.5.1': - resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==} + '@lezer/common@1.5.5': + resolution: {integrity: sha512-Pw7PVCndruF1pb3ebCxpSVpkMHSDjwRCLcTRw+RizUKco5QbWylwq2g4lnG/RYN7yTTQDXE9F77MwtkAyphrjg==} - '@lezer/highlight@1.2.3': - resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + '@lezer/highlight@1.2.5': + resolution: {integrity: sha512-O1GMVKgtf5YspFaRzpmqkVgMtIk2HG9uMAbH6wdAIdNh3TVzCsch/+cRi+6l2//UGDKe6NB9BW3cvuR5ezMQ0w==} '@lezer/json@1.0.3': resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} - '@lezer/lr@1.4.8': - resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} + '@lezer/lr@1.4.12': + resolution: {integrity: sha512-On9HU4oMMiHPMkQDgoTnGahjgG5n/MkN38CgG77sMraKLL+3JBbeQNi1FcCXV9QRqwF9/BUXP3caHyJC1fBOTQ==} + + '@lucide/vue@1.66.0': + resolution: {integrity: sha512-cyALYgAzCD2uZ557pM5I/dmFAyTKqtwY7PrdU67gzITkTH+V635u7Uv7VBpQ5hqvmlGqRtbqSDx08LCJHU+GAw==} + peerDependencies: + vue: '>=3.0.1' - '@marijn/find-cluster-break@1.0.2': - resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@marijn/find-cluster-break@1.0.4': + resolution: {integrity: sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==} - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + '@oxc-project/types@0.156.0': + resolution: {integrity: sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==} + + '@rolldown/binding-android-arm-eabi@1.2.16': + resolution: {integrity: sha512-ia3DwAs0OsMGS7+IConptSiyk9pEXkOx/AbJ2n/lAGxH3QkWQus1t8d7gnAT38FCU2sQu8lUbeR6AiZFv4JxaA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + '@rolldown/binding-android-arm64@1.2.16': + resolution: {integrity: sha512-kx5wBiMB6E7TEvpl2B9gjLU004BkvEm2Dr941BFjx/SontPwSzNuQUIoVKxHHoSjpFIfHMmcguyLOtyn0hObRg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + '@rolldown/binding-darwin-arm64@1.2.16': + resolution: {integrity: sha512-qslZrXnKJU4cUpjoAmtAo/KQM9e2IRMlmpig6Zpwj+8KWxW8v+nkAf9216Bsek9lOC1jvg2yCjygCFo2f83msQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + '@rolldown/binding-darwin-x64@1.2.16': + resolution: {integrity: sha512-FdF+y48ND13eAyM2mQn+85kvAqNlvRWROy2rhgA463X/0Gv4vGtazZtfaF1mRBLscYvtOlh4QnLjOWiFzX69OQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + '@rolldown/binding-freebsd-x64@1.2.16': + resolution: {integrity: sha512-ddjqFM5e95AgLbUPtKIS7V1KTVlA0RUgCVr5mn+/IEhsdy3pr+Vuj/HZ7nlMN2FyxIwUktOH1LEPIQXO1v9y1Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.16': + resolution: {integrity: sha512-tHdKWbFkFBI687iim3LIyIvyL7j66VvQYkDPss5Stn/qyE2tWkR1YD0dXmXPFKKqT/o5ZEJVsaRsWS2meQwGOA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + '@rolldown/binding-linux-arm64-gnu@1.2.16': + resolution: {integrity: sha512-FJiLGAblPBMlBEdbOqw6kW6QcXDWAf/oJu7gYs9ZJZwmg+K+/zjFLxPTIY9izJUzxzc24FHvmseyA0IvJSl17w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + '@rolldown/binding-linux-arm64-musl@1.2.16': + resolution: {integrity: sha512-hrJpblMsrQ58U9veWpbXzkhV5zStunds6HWLprqq1qauvgBr1E6P+24kLj6lSLI9vjRn/RYpjprhkHQPKGWpNg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + '@rolldown/binding-linux-ppc64-gnu@1.2.16': + resolution: {integrity: sha512-qJd/dC6j6CwLG9/s/RP2nb1RZ0GIgj7Ioj7x/SYa3RzjVrlzrmH0fhIOpfvqQDeIsdP0loi+kHaMhJzY1PBIaA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + '@rolldown/binding-linux-s390x-gnu@1.2.16': + resolution: {integrity: sha512-Vx7Xg5uUJuNcujJjI70OICaH0EYj80BtOLZTSN7uOYg8QOLlyKnaG0IW7Fn/J0IpJsaKzmDKMhOQv1JBM9m9vg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + '@rolldown/binding-linux-x64-gnu@1.2.16': + resolution: {integrity: sha512-TNKhgE3uJTsTzatUSSYt0Kgo+Oa2uSlSjz4r1aEIea7HX6ULBym4fAlYUhG1i6pjNf2njfCUAfKwr6C3E9Xg1w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + '@rolldown/binding-linux-x64-musl@1.2.16': + resolution: {integrity: sha512-7chXdpjXZ8qG0+mIxECN3cT9kvhZ3/oZhMX6Pp876P7CDrIy8nJswva6Mq357JR7eYXfuskwZxMeV1SzoZdHrA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + '@rolldown/binding-openharmony-arm64@1.2.16': + resolution: {integrity: sha512-Kwjt+7uNTJK5/MDkGWGVO2KQPnj8yAV75dMpfwyHZrJSXWHrniOB0aUEWlVYf3H1hOqFLIStLdM5QXq6bnKmOQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + '@rolldown/binding-win32-arm64-msvc@1.2.16': + resolution: {integrity: sha512-/LH6WfjDRXXJz/p5xl4TmU+jpcnwcxbKEQBW/GZE0JHfN0lGIyTtsUEGaQ/q/GikkGJ2yLKe6pwm7AnEWO8pdw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + '@rolldown/binding-win32-x64-msvc@1.2.16': + resolution: {integrity: sha512-1lv1KvX0Z871zfk7vw+dnXMMnHNyDwMzWG8Kv3HxDXMOhzCX4SHc7HK319fInP0i+0p9D8brkfzL7pJOaGl+tw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@swc/helpers@0.5.19': - resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -757,129 +575,132 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + '@tailwindcss/vite@4.3.3': + resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} + '@tanstack/store@0.11.2': + resolution: {integrity: sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==} - '@tanstack/virtual-core@3.13.21': - resolution: {integrity: sha512-ww+fmLHyCbPSf7JNbWZP3g7wl6SdNo3ah5Aiw+0e9FDErkVHLKprYUrwTm7dF646FtEkN/KkAKPYezxpmvOjxw==} + '@tanstack/table-core@9.3.1': + resolution: {integrity: sha512-zQvlxSNi2qGM3L4jh85Z6hqMfdIR5qOfD9KHOU32nuKFJGN0RlJ7UvV1lsPb1fPVhpFYI0VP3jJGxLdLDpTKjQ==} + engines: {node: '>=20'} - '@tanstack/vue-table@8.21.3': - resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==} - engines: {node: '>=12'} + '@tanstack/virtual-core@3.19.10': + resolution: {integrity: sha512-/ltpH0qUCs5XQYE7fIhgA+aqgC5NzSfLTDQkC+N1wOOdvIYx1FH/kz2LGfSeanNbekqy3WBu6mNIbqXhxE/pew==} + + '@tanstack/vue-table@9.3.1': + resolution: {integrity: sha512-7z7nS4UP91rLZ01suGxQBT611ogfBrs7/E+lsKeYS9XdHSRUAzclFvQ4B10F0bC/Q8BrzgXiNH3QzumK7b0Tow==} + engines: {node: '>=20'} peerDependencies: vue: '>=3.2' - '@tanstack/vue-virtual@3.13.21': - resolution: {integrity: sha512-zneUNdQTcUhoDl6+ek+/O4S9gSZRAc2q7VLscZ4WZnFfZcHc3M7OyVCfSDC3hGuwFqzfL8Cx5bZF6zbGCYwXmw==} + '@tanstack/vue-virtual@3.13.51': + resolution: {integrity: sha512-0Q57TrTPrNBhQsURZzbDQ4HVC+ukhX/7Ma2h1UXNECyRAHFFRrrEiETtH6TyUHm6E1fmei4HHhu4yAYiTkuviQ==} peerDependencies: vue: ^2.7.0 || ^3.0.0 - '@tauri-apps/api@2.10.1': - resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} + '@tauri-apps/api@2.12.4': + resolution: {integrity: sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg==} - '@tauri-apps/cli-darwin-arm64@2.10.0': - resolution: {integrity: sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==} + '@tauri-apps/cli-darwin-arm64@2.12.4': + resolution: {integrity: sha512-OxqKSckIkoJ6vX2AjifIJpTasFC0Hbdoo7gEiCmAjauABO3U8m2MRsLWe+QTiBwDx1mIrvgA+rvI7tvDnbnHVg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.10.0': - resolution: {integrity: sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==} + '@tauri-apps/cli-darwin-x64@2.12.4': + resolution: {integrity: sha512-fz76/77wMMJOaaUN6n3CybRG0P/MTEjjqYk81mGPyhi9m6Ue5T+LWBnJP/AkPooNatBPI2vtulGqomyMJ44lCQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': - resolution: {integrity: sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.12.4': + resolution: {integrity: sha512-K0w8Bof6Lt8QKLAYhRy0yy36ZH5iA/35VuSOvnxyjvCUZ+A3JKsUTlALviH/sVgAlisaPzzmeJSH8XOn4Q2HBA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': - resolution: {integrity: sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==} + '@tauri-apps/cli-linux-arm64-gnu@2.12.4': + resolution: {integrity: sha512-j5rOnjmRUwWrm1oosf0zBYl4D+fqydgUROFCk0hvKZxvbTT8SOERes0QB7rBV/XWNy+kM6pCKzb3oSm2sRglzg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@2.10.0': - resolution: {integrity: sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==} + '@tauri-apps/cli-linux-arm64-musl@2.12.4': + resolution: {integrity: sha512-aOue3Fy6Jb7+oWcfAVUsVHfeTybSCt2CZoU06aO4jv4d2Ks/KnaTPwMAK3CLEduGOvBLY1lbBBrIyomqLLH5Sg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': - resolution: {integrity: sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==} + '@tauri-apps/cli-linux-riscv64-gnu@2.12.4': + resolution: {integrity: sha512-Fx6GShY/RvST+t6LMlTHAwd66+1tEaAAGrnU7cysVfaiRP1BKng5Vl6rVmO6rSLOA1Sp1dRzNYM4f0OWQGb7qA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-gnu@2.10.0': - resolution: {integrity: sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==} + '@tauri-apps/cli-linux-x64-gnu@2.12.4': + resolution: {integrity: sha512-tNzZSa79Z1nRpHxEpQ38lsAFpKlFlYvoXzjTV+lRRn/zSf3wrdUC3wnLcq2XEadchPu4ttK0zivhYzr+XGD19Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@2.10.0': - resolution: {integrity: sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==} + '@tauri-apps/cli-linux-x64-musl@2.12.4': + resolution: {integrity: sha512-jmZ1pr0xEqUhuEusWtt9Yt+GF6lCnGHUmIL+KIknpbjK/XQ2qkhDBhaxK/JMHM2A8dAacVXCxXJk2EXpwhQUfA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': - resolution: {integrity: sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==} + '@tauri-apps/cli-win32-arm64-msvc@2.12.4': + resolution: {integrity: sha512-fGo8pgEHZxdSYgZ/J98m1usJ7NHKmKbq7k6uT0x1rpOq6Bg2YVzzpaAblWk710f5LHYBJIL5QIFS5IrD+4gmTg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': - resolution: {integrity: sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==} + '@tauri-apps/cli-win32-ia32-msvc@2.12.4': + resolution: {integrity: sha512-ezl8sQIcjYsye3TUnTH5VcWmWzccZASlQm7hlZt0dYyj1XD0qpVW47u2xYVrIKui0F8uQv/7QGZixdWiClBsbg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.10.0': - resolution: {integrity: sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==} + '@tauri-apps/cli-win32-x64-msvc@2.12.4': + resolution: {integrity: sha512-DJhDeCqjLDNMWYFy7ZS8cfeAHX2RK0RbQMLiA3bMVVkXRDJ4NBYiHriGqsUhsr9iG41aTb+dJGkFPmPw1gWwVw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.10.0': - resolution: {integrity: sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==} + '@tauri-apps/cli@2.12.4': + resolution: {integrity: sha512-JI9bHfudSRJikGOrjbXEm6RjzzvmKuLc+JixB1NE8hNzQkNlCCIC3pTES3uypkR9lxHrsbxzcnSwhI2IxBQphw==} engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-log@2.8.0': - resolution: {integrity: sha512-a+7rOq3MJwpTOLLKbL8d0qGZ85hgHw5pNOWusA9o3cf7cEgtYHiGY/+O8fj8MvywQIGqFv0da2bYQDlrqLE7rw==} + '@tauri-apps/plugin-log@2.10.1': + resolution: {integrity: sha512-QYgxDunUZP+Cd3ev+8ItOc3Q6uUFkEhRHdTolxUtlC/8SGsc5IyVjGgFclprkAx736HUCUYfh2vqUr3qwNfTTw==} - '@tauri-apps/plugin-opener@2.5.3': - resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==} + '@tauri-apps/plugin-opener@2.7.2': + resolution: {integrity: sha512-LyybP1VSzTMQiaFYcsbAse47KpivlyXdLZMQzGLEnkgQacGESnpjAfFoQ6h5sqWgAdZDH9szYjPzHMpv0Sz+TQ==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -887,129 +708,148 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.10': + resolution: {integrity: sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==} - '@types/node@25.3.3': - resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==} + '@types/node@26.6.6': + resolution: {integrity: sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==} '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + + '@types/ws@8.18.2': + resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} + '@vee-validate/zod@4.15.1': resolution: {integrity: sha512-329Z4TDBE5Vx0FdbA8S4eR9iGCFFUNGbxjpQ20ff5b5wGueScjocUIx9JHPa79LTG06RnlUR4XogQsjN4tecKA==} peerDependencies: zod: ^3.24.0 - '@vitejs/plugin-vue@5.2.4': - resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} - engines: {node: ^18.0.0 || >=20.0.0} + '@vitejs/plugin-vue@6.0.10': + resolution: {integrity: sha512-b80aUQh3n+qEzzZm5oQp3rT2QImeCx58K6eFl/RkJ3d65KW0kTuv5lNsLRVAjbW9YRUpo/wzmvzMgV34bTAItA==} + engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 || ^3.6.0-rc.10 - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@5.0.5': + resolution: {integrity: sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==} peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + msw: ^2.4.9 || ^3.0.0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/spy@5.0.5': + resolution: {integrity: sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==} + + '@volar/language-core@2.4.30': + resolution: {integrity: sha512-73fjwEV8wat6aOZ6U/y/hqtE30ocrIWECg67b0txGczOMNw+MffLmvJ5fnFfN9drVUEYZzLdaNo6VAy6G6avMw==} + + '@volar/language-service@2.4.30': + resolution: {integrity: sha512-w/xDsASiqC71ggCOm7sTDXDNk/l72XEptodeRC68tgZ0e5QM4hM3zAqBGC7mBctvhrpYwKfMG+t9xcUo2hEFtA==} + peerDependencies: + typescript: <7 + peerDependenciesMeta: + typescript: + optional: true - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@volar/source-map@2.4.30': + resolution: {integrity: sha512-zym1ob/KwDDyN+0jGVtxwbxJSRRnUvv5HspCtz3yEfVVdCG4/dzxJktMGPAgemqRuVs81O0o/y0q3qOUErR8kg==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@volar/typescript@2.4.30': + resolution: {integrity: sha512-/DgA5tgYFPfrLFuSjIMXMGHk1LQv2+P8eny6+BhGNzFJELWIW7UZlc56ZLIRFhLsPpMfIFxM8/HvOPBggrjTZg==} + peerDependencies: + typescript: <7 + peerDependenciesMeta: + typescript: + optional: true - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vue/compiler-core@3.5.44': + resolution: {integrity: sha512-k34nCytbK8PQ1gR2mGROYOw6Pnv/mumqIdrZ3x2tbyXZDWm7ViKGLTfdB+DRrWqEQsLgGJvn0WN9jBif5zCTLQ==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vue/compiler-dom@3.5.44': + resolution: {integrity: sha512-W5AoBFWdw1lQAKiHowkfgFKFab82oSRT6sGsPfw/q1GRjsy/ZJFLHGhJyBRIFN9APLTUduDH9U2JAiPOIyKuYg==} - '@volar/language-core@2.4.15': - resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} + '@vue/compiler-sfc@3.5.44': + resolution: {integrity: sha512-dzHmQ4jXTpdr5FjIQUeykVakN/uzqFbUo9/C5ikBFg3a3PeM6uRxeczx1ZbXBML0/zJstEh3ygYipzR5Z7b2Pw==} - '@volar/source-map@2.4.15': - resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} + '@vue/compiler-ssr@3.5.44': + resolution: {integrity: sha512-xr5gb1JVHlfXJwSlRz1FeP6uxoazdzHuMTVLE7up+4Vrqxk219CvxLPxD9NXBt47yvZW7+p4DXfyp4O1fkByIA==} - '@volar/typescript@2.4.15': - resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} + '@vue/devtools-api@7.7.10': + resolution: {integrity: sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==} - '@vue/compiler-core@3.5.29': - resolution: {integrity: sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw==} + '@vue/devtools-api@8.2.1': + resolution: {integrity: sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A==} - '@vue/compiler-dom@3.5.29': - resolution: {integrity: sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg==} + '@vue/devtools-kit@7.7.10': + resolution: {integrity: sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==} - '@vue/compiler-sfc@3.5.29': - resolution: {integrity: sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA==} + '@vue/devtools-kit@8.2.1': + resolution: {integrity: sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==} - '@vue/compiler-ssr@3.5.29': - resolution: {integrity: sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw==} + '@vue/devtools-shared@7.7.10': + resolution: {integrity: sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==} - '@vue/compiler-vue2@2.7.16': - resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + '@vue/devtools-shared@8.2.1': + resolution: {integrity: sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==} - '@vue/devtools-api@7.7.9': - resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + '@vue/language-core@3.3.14': + resolution: {integrity: sha512-kRB+3hHg0c+BdD1XLAvwjVMQd5pC05zijSlPDRI3ERvC/s04JlRs5upy2KjeMg/9m9oD5zuMVh9yVvkKfZqoJg==} - '@vue/devtools-kit@7.7.9': - resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + '@vue/reactivity@3.5.44': + resolution: {integrity: sha512-u+QJdKeBBEADkPdevsL+6E12QlYVfBD8Zcw5qjDQKtamI6l14KyqazJMobhCKelhWN5zpyKUiEDoTyHE93cqWw==} - '@vue/devtools-shared@7.7.9': - resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + '@vue/runtime-core@3.5.44': + resolution: {integrity: sha512-uEa/ndwjhrrhnOfb2p+sZy6zeoamJOISqaLSJGk/8R6nABT1ZldpzcJoPzKj+zHVomVBPcmQYyC2r4LtvDV6CQ==} - '@vue/language-core@2.2.12': - resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@vue/runtime-dom@3.5.44': + resolution: {integrity: sha512-3fc4ARcXVhVBaJ3ujWiNZJARD6pkyRcwG+ZYhMzjKtKUp7MAY0HLwr7r3Smep3Li6ZaWT6ewdmx8XqdaD5oNZg==} - '@vue/reactivity@3.5.29': - resolution: {integrity: sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==} + '@vue/server-renderer@3.5.44': + resolution: {integrity: sha512-R4S1UoH4h5Frrauv8Z5XE5TxV9oBiUSgWIC4TyVK1FK+RocRnOLwFA5Xcmo2011RlgJp+AbZCnw6afrhlgRuUQ==} - '@vue/runtime-core@3.5.29': - resolution: {integrity: sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==} + '@vue/shared@3.5.44': + resolution: {integrity: sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg==} - '@vue/runtime-dom@3.5.29': - resolution: {integrity: sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==} + '@vueuse/core@14.4.0': + resolution: {integrity: sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==} + peerDependencies: + vue: ^3.5.0 - '@vue/server-renderer@3.5.29': - resolution: {integrity: sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g==} + '@vueuse/core@15.0.0': + resolution: {integrity: sha512-Zv67h5mrk7YHDJsRObx+DXaCBz6RKBUpxqLesJ+3xZNPG6yuQs7ja7kg3veFrrouYLWAqydQ7CwGEbLVxB43Ng==} + engines: {node: '>=22'} peerDependencies: - vue: 3.5.29 + vue: ^3.5.0 - '@vue/shared@3.5.29': - resolution: {integrity: sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==} + '@vueuse/metadata@14.4.0': + resolution: {integrity: sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==} - '@vueuse/core@14.2.1': - resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} + '@vueuse/metadata@15.0.0': + resolution: {integrity: sha512-sfWE5LADAKJ0KnjtGliMdSN8Ij/L7uP6rXIZlgPloAI4zvvefbw6H5Lt7KJA6RqQOYgVqWF5Guj50HHMIzygBg==} + engines: {node: '>=22'} + + '@vueuse/shared@14.4.0': + resolution: {integrity: sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==} peerDependencies: vue: ^3.5.0 - '@vueuse/metadata@14.2.1': - resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} - - '@vueuse/shared@14.2.1': - resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} + '@vueuse/shared@15.0.0': + resolution: {integrity: sha512-vbNXhGrbV53xPOMSyOzMHQRvhMgZf7oNDw2RChUetVxwTIEkInQ1joZ9JbT0G3z2n2AJNjvmCWeM9ySYrnvogA==} + engines: {node: '>=22'} peerDependencies: vue: ^3.5.0 - alien-signals@1.0.13: - resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} @@ -1019,17 +859,15 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + buffer-image-size@0.6.4: + resolution: {integrity: sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==} + engines: {node: '>=4.0'} - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} class-variance-authority@0.7.1: @@ -1042,41 +880,33 @@ packages: codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} - copy-anything@4.0.5: - resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + copy-anything@4.1.5: + resolution: {integrity: sha512-vePst2VLTSqPglW7Q98VwFpGiGpOHTyXIo81MO5VyLecA5zMbZw/P/V1vmwD1jksa2iJpn/YkDrJ3XhTfzUyhQ==} engines: {node: '>=18'} - crelt@1.0.6: - resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - enhanced-resolve@5.20.0: - resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} engines: {node: '>=10.13.0'} entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -1084,8 +914,8 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} fdir@6.5.0: @@ -1105,106 +935,170 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true + happy-dom@21.0.4: + resolution: {integrity: sha512-tFm+GaLBgo6o0awHnvHaNoraVo27qJ+2tZEtZ+cIa08hXbeitrxAJajLI05hsUy/2/YTKcUjQYzHe5mCcraLBw==} + engines: {node: '>=20.0.0'} hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} - is-what@5.5.0: - resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} - engines: {node: '>=18'} - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + 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.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + 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.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + 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.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + 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.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + 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.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + 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.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + 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.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + 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.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + 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.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - lucide-vue-next@0.563.0: - resolution: {integrity: sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA==} - peerDependencies: - vue: '>=3.0.1' + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} + magic-string@1.4.5: + resolution: {integrity: sha512-oLLC2+YvQUfAa+vxoufE/yc1icb87M9iXIRqAoR/2EhE/8cb3SF/+Gi0c2By1B+5Vz2e2vQtUvHiu1+63Znh+w==} mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} @@ -1212,110 +1106,106 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + nostics@1.3.0: + resolution: {integrity: sha512-wzRsrJwNlFbqIRQt8aCeL2WE8USip/uuvGSOZV1D02CxX8ABTMbw8IywKjH7yWHETMXbWJI4OBpihg9rmz2Vyg==} - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + obug@3.0.0: + resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} + engines: {node: '>=12.20.0'} + + ohash@2.0.12: + resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} - pinia@3.0.4: - resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} + pinia@4.1.0: + resolution: {integrity: sha512-+5/HMuVjYQfKlCD5xQ7zfXn1xUzYFEa7pd0DQK5SaMfZCaFRTHlaH/c02N1FoGOdlzSiwf5EOPgJx//1QDw6gw==} peerDependencies: - typescript: '>=4.5.0' + '@vue/devtools-api': ^8.2.1 + typescript: '>=5.6.0' vue: ^3.5.11 peerDependenciesMeta: typescript: optional: true - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.32: + resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==} engines: {node: ^10 || ^12 || >=14} - reka-ui@2.8.2: - resolution: {integrity: sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA==} + reka-ui@2.11.0: + resolution: {integrity: sha512-ilkpm4bIAol4jwzm4tpm3WVcffyGOpqksNZL1k1qO9QmIwAA+q8jroxjkUGLEn/GddfdExFfvofWfQiKZszUeQ==} peerDependencies: - vue: '>= 3.2.0' + vue: '>= 3.4.0' rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown@1.2.16: + resolution: {integrity: sha512-bWvlMpFKiTfDKfnK7FC2MPgPeWCf/Kpwsq49ApdW+FQaBZb6O6dZ4MAPbPUjp7hYQrw/RobqCzn64BRrQecGHw==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} speakingurl@14.0.1: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} - style-mod@4.1.3: - resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + style-mod@4.1.4: + resolution: {integrity: sha512-XXWIQt633/EpAFx8aZDOTjBzrCaGmhvEQlQo6MVPfa2OzO2cWo+4hV9h+6UkHYlXGfy+ODXKUdP7Pthmcu5ATw==} superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} - tailwind-merge@3.5.0: - resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + tailwind-merge@3.7.0: + resolution: {integrity: sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==} - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinybench@6.2.3: + resolution: {integrity: sha512-Al01C2JIBnO2CXCAPbpAl6sUiOZHeThGtHYNTa51JRw9PyWOCdr+9Ong05R4qg/Sk3+H645E8ov1h2c58ityNw==} + engines: {node: '>=20.0.0'} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tslib@2.9.1: + resolution: {integrity: sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==} tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} @@ -1324,44 +1214,47 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} vee-validate@4.15.1: resolution: {integrity: sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg==} peerDependencies: vue: ^3.4.26 - vite@6.4.1: - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@8.3.5: + resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 || ^0.8.0 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + 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 - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -1377,20 +1270,23 @@ packages: yaml: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vitest@5.0.5: + resolution: {integrity: sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.5 + '@vitest/browser-preview': 5.0.5 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.5 + '@vitest/coverage-v8': 5.0.5 + '@vitest/ui': 5.0.5 happy-dom: '*' jsdom: '*' + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -1404,6 +1300,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -1411,19 +1311,21 @@ packages: jsdom: optional: true - vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vscode-jsonrpc@10.0.0: + resolution: {integrity: sha512-USSfxg0vDIpTQqlQBGxF3mBARyoS8cU7LHLpbYNh6dOJt32dlskxPWB0Irrh5TllTmyf7oNLAvqDqzklbwwnpA==} + engines: {node: '>=14.17.0'} - vue-demi@0.14.10: - resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} - engines: {node: '>=12'} - hasBin: true - peerDependencies: - '@vue/composition-api': ^1.0.0-rc.1 - vue: ^3.0.0-0 || ^2.6.0 - peerDependenciesMeta: - '@vue/composition-api': - optional: true + vscode-languageserver-protocol@3.18.5: + resolution: {integrity: sha512-FW4fBMzZ99N8xeob4py0l050wgCoRgTpEq5Xcsb9lM1bc29UKGR/wSV+4knaqFxssFHajy7OzNiKP/m3U1ZEuA==} + + vscode-languageserver-textdocument@1.0.16: + resolution: {integrity: sha512-qeNEuOi9a3qkqRf7Gfez2WL2VwlBTLCNekHBGO9kxPVUp9XuY15yfTJ9jwvOwKI0I2MhUUfZq95NSp+LK1CLQg==} + + vscode-languageserver-types@3.18.5: + resolution: {integrity: sha512-kPd6+JQNz3HMJvjKlqUxERSlZHAntl/aGpsk7ImwIh0ewDKDcjgAEyVSYciPiOJD3ftbK9IrfiqUeTZLSbCizw==} + + vscode-uri@3.2.0: + resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} vue-sonner@2.0.9: resolution: {integrity: sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==} @@ -1439,14 +1341,14 @@ packages: nuxt: optional: true - vue-tsc@2.2.12: - resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} + vue-tsc@3.3.14: + resolution: {integrity: sha512-URAu2H9AuMZMg9GCgnqbaHHHd8pBZRAwNV2e2yYS8VDsoTVXHiOSo663OS6DkEvauQ2yixn5TPFJ9WV9QIspkA==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.29: - resolution: {integrity: sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==} + vue@3.5.44: + resolution: {integrity: sha512-dvvmaOCG7lAMkJTPqPwWeGMsPS6DIsFsfZDUgBp9V6mHf9b3+/wyVwYR4Es+WV6uJC0FKRxp81Obcq0ZwUcGFQ==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -1456,196 +1358,134 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + why-is-node-running@3.2.1: + resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} + engines: {node: '>=20.11'} hasBin: true + ws@8.22.1: + resolution: {integrity: sha512-oyL6OPYme/CmiFvNuGzeoxCJ4nOrZE2O1FwM9MWM1AsGri6nLXB2pg+lNA8aLeXMSav0J6eIVS1j6vUPzUtK9g==} + 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 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} snapshots: - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.11': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/parser@7.29.0': + '@babel/parser@7.29.12': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.11 - '@babel/types@7.29.0': + '@babel/types@7.29.11': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.11 + '@babel/helper-validator-identifier': 7.29.7 - '@codemirror/autocomplete@6.20.1': + '@codemirror/autocomplete@6.20.4': dependencies: - '@codemirror/language': 6.12.2 - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - '@lezer/common': 1.5.1 + '@codemirror/language': 6.13.1 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.5 - '@codemirror/commands@6.10.2': + '@codemirror/commands@6.11.1': dependencies: - '@codemirror/language': 6.12.2 - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - '@lezer/common': 1.5.1 + '@codemirror/language': 6.13.1 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.5 '@codemirror/lang-json@6.0.2': dependencies: - '@codemirror/language': 6.12.2 + '@codemirror/language': 6.13.1 '@lezer/json': 1.0.3 - '@codemirror/language@6.12.2': + '@codemirror/language@6.13.1': dependencies: - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - '@lezer/common': 1.5.1 - '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 - style-mod: 4.1.3 + '@codemirror/state': 6.7.6 + '@codemirror/streamparser': 6.0.0 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.5 + '@lezer/highlight': 1.2.5 + '@lezer/lr': 1.4.12 + style-mod: 4.1.4 - '@codemirror/lint@6.9.5': + '@codemirror/lint@6.9.7': dependencies: - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - crelt: 1.0.6 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + crelt: 1.0.7 - '@codemirror/search@6.6.0': + '@codemirror/search@6.7.2': dependencies: - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - crelt: 1.0.6 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + crelt: 1.0.7 - '@codemirror/state@6.5.4': + '@codemirror/state@6.7.6': dependencies: - '@marijn/find-cluster-break': 1.0.2 + '@marijn/find-cluster-break': 1.0.4 + + '@codemirror/streamparser@6.0.0': {} '@codemirror/theme-one-dark@6.1.3': dependencies: - '@codemirror/language': 6.12.2 - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 - '@lezer/highlight': 1.2.3 + '@codemirror/language': 6.13.1 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + '@lezer/highlight': 1.2.5 - '@codemirror/view@6.39.16': + '@codemirror/view@6.43.15': dependencies: - '@codemirror/state': 6.5.4 - crelt: 1.0.6 - style-mod: 4.1.3 + '@codemirror/state': 6.7.6 + crelt: 1.0.7 + style-mod: 4.1.4 w3c-keyname: 2.2.8 - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-mips64el@0.25.12': - optional: true - - '@esbuild/linux-ppc64@0.25.12': - optional: true - - '@esbuild/linux-riscv64@0.25.12': - optional: true - - '@esbuild/linux-s390x@0.25.12': - optional: true - - '@esbuild/linux-x64@0.25.12': - optional: true - - '@esbuild/netbsd-arm64@0.25.12': - optional: true - - '@esbuild/netbsd-x64@0.25.12': - optional: true - - '@esbuild/openbsd-arm64@0.25.12': - optional: true - - '@esbuild/openbsd-x64@0.25.12': - optional: true - - '@esbuild/openharmony-arm64@0.25.12': - optional: true - - '@esbuild/sunos-x64@0.25.12': - optional: true - - '@esbuild/win32-arm64@0.25.12': - optional: true - - '@esbuild/win32-ia32@0.25.12': - optional: true - - '@esbuild/win32-x64@0.25.12': - optional: true - - '@floating-ui/core@1.7.4': + '@floating-ui/core@1.8.0': dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.12 - '@floating-ui/dom@1.7.5': + '@floating-ui/dom@1.8.0': dependencies: - '@floating-ui/core': 1.7.4 - '@floating-ui/utils': 0.2.10 + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 - '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.12': {} - '@floating-ui/vue@1.1.10(vue@3.5.29(typescript@5.6.3))': + '@floating-ui/vue@2.0.1(vue@3.5.44(typescript@6.0.3))': dependencies: - '@floating-ui/dom': 1.7.5 - '@floating-ui/utils': 0.2.10 - vue-demi: 0.14.10(vue@3.5.29(typescript@5.6.3)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue + '@floating-ui/dom': 1.8.0 + '@floating-ui/utils': 0.2.12 + vue: 3.5.44(typescript@6.0.3) - '@internationalized/date@3.11.0': + '@internationalized/date@3.12.4': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.23 - '@internationalized/number@3.6.5': + '@internationalized/number@3.6.9': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.23 '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': @@ -1655,250 +1495,231 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 - '@lezer/common@1.5.1': {} + '@lezer/common@1.5.5': {} - '@lezer/highlight@1.2.3': + '@lezer/highlight@1.2.5': dependencies: - '@lezer/common': 1.5.1 + '@lezer/common': 1.5.5 '@lezer/json@1.0.3': dependencies: - '@lezer/common': 1.5.1 - '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/common': 1.5.5 + '@lezer/highlight': 1.2.5 + '@lezer/lr': 1.4.12 - '@lezer/lr@1.4.8': + '@lezer/lr@1.4.12': dependencies: - '@lezer/common': 1.5.1 - - '@marijn/find-cluster-break@1.0.2': {} - - '@rollup/rollup-android-arm-eabi@4.59.0': - optional: true - - '@rollup/rollup-android-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-x64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - optional: true + '@lezer/common': 1.5.5 - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - optional: true + '@lucide/vue@1.66.0(vue@3.5.44(typescript@6.0.3))': + dependencies: + vue: 3.5.44(typescript@6.0.3) - '@rollup/rollup-linux-arm64-gnu@4.59.0': - optional: true + '@marijn/find-cluster-break@1.0.4': {} - '@rollup/rollup-linux-arm64-musl@4.59.0': - optional: true + '@oxc-project/types@0.156.0': {} - '@rollup/rollup-linux-loong64-gnu@4.59.0': + '@rolldown/binding-android-arm-eabi@1.2.16': optional: true - '@rollup/rollup-linux-loong64-musl@4.59.0': + '@rolldown/binding-android-arm64@1.2.16': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': + '@rolldown/binding-darwin-arm64@1.2.16': optional: true - '@rollup/rollup-linux-ppc64-musl@4.59.0': + '@rolldown/binding-darwin-x64@1.2.16': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': + '@rolldown/binding-freebsd-x64@1.2.16': optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': + '@rolldown/binding-linux-arm-gnueabihf@1.2.16': optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': + '@rolldown/binding-linux-arm64-gnu@1.2.16': optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': + '@rolldown/binding-linux-arm64-musl@1.2.16': optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': + '@rolldown/binding-linux-ppc64-gnu@1.2.16': optional: true - '@rollup/rollup-openbsd-x64@4.59.0': + '@rolldown/binding-linux-s390x-gnu@1.2.16': optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': + '@rolldown/binding-linux-x64-gnu@1.2.16': optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': + '@rolldown/binding-linux-x64-musl@1.2.16': optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': + '@rolldown/binding-openharmony-arm64@1.2.16': optional: true - '@rollup/rollup-win32-x64-gnu@4.59.0': + '@rolldown/binding-win32-arm64-msvc@1.2.16': optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': + '@rolldown/binding-win32-x64-msvc@1.2.16': optional: true - '@standard-schema/spec@1.1.0': {} + '@rolldown/pluginutils@1.0.1': {} - '@swc/helpers@0.5.19': + '@swc/helpers@0.5.23': dependencies: - tslib: 2.8.1 + tslib: 2.9.1 - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.0 - jiti: 2.6.1 - lightningcss: 1.31.1 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.2.1 + source-map-js: 1.2.2 + tailwindcss: 4.3.3 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.3.3': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.3.3': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.3.3': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.3.3': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/vite@4.2.1(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1))': + '@tailwindcss/vite@4.3.3(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0))': dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + vite: 8.3.5(@types/node@26.6.6)(jiti@2.7.0) - '@tanstack/table-core@8.21.3': {} + '@tanstack/store@0.11.2': {} - '@tanstack/virtual-core@3.13.21': {} + '@tanstack/table-core@9.3.1': + dependencies: + '@tanstack/store': 0.11.2 + + '@tanstack/virtual-core@3.19.10': {} - '@tanstack/vue-table@8.21.3(vue@3.5.29(typescript@5.6.3))': + '@tanstack/vue-table@9.3.1(vue@3.5.44(typescript@6.0.3))': dependencies: - '@tanstack/table-core': 8.21.3 - vue: 3.5.29(typescript@5.6.3) + '@tanstack/store': 0.11.2 + '@tanstack/table-core': 9.3.1 + vue: 3.5.44(typescript@6.0.3) - '@tanstack/vue-virtual@3.13.21(vue@3.5.29(typescript@5.6.3))': + '@tanstack/vue-virtual@3.13.51(vue@3.5.44(typescript@6.0.3))': dependencies: - '@tanstack/virtual-core': 3.13.21 - vue: 3.5.29(typescript@5.6.3) + '@tanstack/virtual-core': 3.19.10 + vue: 3.5.44(typescript@6.0.3) - '@tauri-apps/api@2.10.1': {} + '@tauri-apps/api@2.12.4': {} - '@tauri-apps/cli-darwin-arm64@2.10.0': + '@tauri-apps/cli-darwin-arm64@2.12.4': optional: true - '@tauri-apps/cli-darwin-x64@2.10.0': + '@tauri-apps/cli-darwin-x64@2.12.4': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': + '@tauri-apps/cli-linux-arm-gnueabihf@2.12.4': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': + '@tauri-apps/cli-linux-arm64-gnu@2.12.4': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.10.0': + '@tauri-apps/cli-linux-arm64-musl@2.12.4': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': + '@tauri-apps/cli-linux-riscv64-gnu@2.12.4': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.10.0': + '@tauri-apps/cli-linux-x64-gnu@2.12.4': optional: true - '@tauri-apps/cli-linux-x64-musl@2.10.0': + '@tauri-apps/cli-linux-x64-musl@2.12.4': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': + '@tauri-apps/cli-win32-arm64-msvc@2.12.4': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': + '@tauri-apps/cli-win32-ia32-msvc@2.12.4': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.10.0': + '@tauri-apps/cli-win32-x64-msvc@2.12.4': optional: true - '@tauri-apps/cli@2.10.0': + '@tauri-apps/cli@2.12.4': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.10.0 - '@tauri-apps/cli-darwin-x64': 2.10.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.10.0 - '@tauri-apps/cli-linux-arm64-gnu': 2.10.0 - '@tauri-apps/cli-linux-arm64-musl': 2.10.0 - '@tauri-apps/cli-linux-riscv64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-musl': 2.10.0 - '@tauri-apps/cli-win32-arm64-msvc': 2.10.0 - '@tauri-apps/cli-win32-ia32-msvc': 2.10.0 - '@tauri-apps/cli-win32-x64-msvc': 2.10.0 + '@tauri-apps/cli-darwin-arm64': 2.12.4 + '@tauri-apps/cli-darwin-x64': 2.12.4 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.12.4 + '@tauri-apps/cli-linux-arm64-gnu': 2.12.4 + '@tauri-apps/cli-linux-arm64-musl': 2.12.4 + '@tauri-apps/cli-linux-riscv64-gnu': 2.12.4 + '@tauri-apps/cli-linux-x64-gnu': 2.12.4 + '@tauri-apps/cli-linux-x64-musl': 2.12.4 + '@tauri-apps/cli-win32-arm64-msvc': 2.12.4 + '@tauri-apps/cli-win32-ia32-msvc': 2.12.4 + '@tauri-apps/cli-win32-x64-msvc': 2.12.4 - '@tauri-apps/plugin-log@2.8.0': + '@tauri-apps/plugin-log@2.10.1': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 - '@tauri-apps/plugin-opener@2.5.3': + '@tauri-apps/plugin-opener@2.7.2': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 '@types/chai@5.2.3': dependencies: @@ -1907,120 +1728,110 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.10': {} - '@types/node@25.3.3': + '@types/node@26.6.6': dependencies: - undici-types: 7.18.2 + undici-types: 8.9.0 '@types/web-bluetooth@0.0.21': {} - '@vee-validate/zod@4.15.1(vue@3.5.29(typescript@5.6.3))(zod@3.25.76)': + '@types/whatwg-mimetype@3.0.2': {} + + '@types/ws@8.18.2': + dependencies: + '@types/node': 26.6.6 + + '@vee-validate/zod@4.15.1(vue@3.5.44(typescript@6.0.3))(zod@3.25.76)': dependencies: type-fest: 4.41.0 - vee-validate: 4.15.1(vue@3.5.29(typescript@5.6.3)) + vee-validate: 4.15.1(vue@3.5.44(typescript@6.0.3)) zod: 3.25.76 transitivePeerDependencies: - vue - '@vitejs/plugin-vue@5.2.4(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1))(vue@3.5.29(typescript@5.6.3))': + '@vitejs/plugin-vue@6.0.10(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0))(vue@3.5.44(typescript@6.0.3))': dependencies: - vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) - vue: 3.5.29(typescript@5.6.3) + '@rolldown/pluginutils': 1.0.1 + vite: 8.3.5(@types/node@26.6.6)(jiti@2.7.0) + vue: 3.5.44(typescript@6.0.3) - '@vitest/expect@4.0.18': + '@vitest/mocker@5.0.5(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0))': dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - - '@vitest/mocker@4.0.18(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1))': - dependencies: - '@vitest/spy': 4.0.18 + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.5 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 1.4.5 optionalDependencies: - vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) + vite: 8.3.5(@types/node@26.6.6)(jiti@2.7.0) - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 + '@vitest/spy@5.0.5': {} - '@vitest/runner@4.0.18': + '@volar/language-core@2.4.30': dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 + '@volar/source-map': 2.4.30 - '@vitest/snapshot@4.0.18': + '@volar/language-service@2.4.30(typescript@6.0.3)': dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.0.18': {} - - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - '@volar/language-core@2.4.15': - dependencies: - '@volar/source-map': 2.4.15 + '@volar/language-core': 2.4.30 + vscode-languageserver-protocol: 3.18.5 + vscode-languageserver-textdocument: 1.0.16 + vscode-uri: 3.2.0 + optionalDependencies: + typescript: 6.0.3 - '@volar/source-map@2.4.15': {} + '@volar/source-map@2.4.30': {} - '@volar/typescript@2.4.15': + '@volar/typescript@2.4.30(typescript@6.0.3)': dependencies: - '@volar/language-core': 2.4.15 + '@volar/language-core': 2.4.30 + '@volar/language-service': 2.4.30(typescript@6.0.3) path-browserify: 1.0.1 - vscode-uri: 3.1.0 + vscode-uri: 3.2.0 + optionalDependencies: + typescript: 6.0.3 - '@vue/compiler-core@3.5.29': + '@vue/compiler-core@3.5.44': dependencies: - '@babel/parser': 7.29.0 - '@vue/shared': 3.5.29 + '@babel/parser': 7.29.12 + '@vue/shared': 3.5.44 entities: 7.0.1 estree-walker: 2.0.2 - source-map-js: 1.2.1 + source-map-js: 1.2.2 - '@vue/compiler-dom@3.5.29': + '@vue/compiler-dom@3.5.44': dependencies: - '@vue/compiler-core': 3.5.29 - '@vue/shared': 3.5.29 + '@vue/compiler-core': 3.5.44 + '@vue/shared': 3.5.44 - '@vue/compiler-sfc@3.5.29': + '@vue/compiler-sfc@3.5.44': dependencies: - '@babel/parser': 7.29.0 - '@vue/compiler-core': 3.5.29 - '@vue/compiler-dom': 3.5.29 - '@vue/compiler-ssr': 3.5.29 - '@vue/shared': 3.5.29 + '@babel/parser': 7.29.12 + '@vue/compiler-core': 3.5.44 + '@vue/compiler-dom': 3.5.44 + '@vue/compiler-ssr': 3.5.44 + '@vue/shared': 3.5.44 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 + postcss: 8.5.32 + source-map-js: 1.2.2 - '@vue/compiler-ssr@3.5.29': + '@vue/compiler-ssr@3.5.44': dependencies: - '@vue/compiler-dom': 3.5.29 - '@vue/shared': 3.5.29 + '@vue/compiler-dom': 3.5.44 + '@vue/shared': 3.5.44 - '@vue/compiler-vue2@2.7.16': + '@vue/devtools-api@7.7.10': dependencies: - de-indent: 1.0.2 - he: 1.2.0 + '@vue/devtools-kit': 7.7.10 - '@vue/devtools-api@7.7.9': + '@vue/devtools-api@8.2.1': dependencies: - '@vue/devtools-kit': 7.7.9 + '@vue/devtools-kit': 8.2.1 - '@vue/devtools-kit@7.7.9': + '@vue/devtools-kit@7.7.10': dependencies: - '@vue/devtools-shared': 7.7.9 + '@vue/devtools-shared': 7.7.10 birpc: 2.9.0 hookable: 5.5.3 mitt: 3.0.1 @@ -2028,77 +1839,94 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.6 - '@vue/devtools-shared@7.7.9': + '@vue/devtools-kit@8.2.1': + dependencies: + '@vue/devtools-shared': 8.2.1 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@7.7.10': dependencies: rfdc: 1.4.1 - '@vue/language-core@2.2.12(typescript@5.6.3)': + '@vue/devtools-shared@8.2.1': {} + + '@vue/language-core@3.3.14': dependencies: - '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.29 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.29 - alien-signals: 1.0.13 - minimatch: 9.0.9 + '@volar/language-core': 2.4.30 + '@vue/compiler-dom': 3.5.44 + '@vue/shared': 3.5.44 + alien-signals: 3.2.1 muggle-string: 0.4.1 path-browserify: 1.0.1 - optionalDependencies: - typescript: 5.6.3 + picomatch: 4.0.7 - '@vue/reactivity@3.5.29': + '@vue/reactivity@3.5.44': dependencies: - '@vue/shared': 3.5.29 + '@vue/shared': 3.5.44 - '@vue/runtime-core@3.5.29': + '@vue/runtime-core@3.5.44': dependencies: - '@vue/reactivity': 3.5.29 - '@vue/shared': 3.5.29 + '@vue/reactivity': 3.5.44 + '@vue/shared': 3.5.44 - '@vue/runtime-dom@3.5.29': + '@vue/runtime-dom@3.5.44': dependencies: - '@vue/reactivity': 3.5.29 - '@vue/runtime-core': 3.5.29 - '@vue/shared': 3.5.29 + '@vue/reactivity': 3.5.44 + '@vue/runtime-core': 3.5.44 + '@vue/shared': 3.5.44 csstype: 3.2.3 - '@vue/server-renderer@3.5.29(vue@3.5.29(typescript@5.6.3))': + '@vue/server-renderer@3.5.44': dependencies: - '@vue/compiler-ssr': 3.5.29 - '@vue/shared': 3.5.29 - vue: 3.5.29(typescript@5.6.3) + '@vue/compiler-ssr': 3.5.44 + '@vue/runtime-dom': 3.5.44 + '@vue/shared': 3.5.44 - '@vue/shared@3.5.29': {} + '@vue/shared@3.5.44': {} - '@vueuse/core@14.2.1(vue@3.5.29(typescript@5.6.3))': + '@vueuse/core@14.4.0(vue@3.5.44(typescript@6.0.3))': dependencies: '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.2.1 - '@vueuse/shared': 14.2.1(vue@3.5.29(typescript@5.6.3)) - vue: 3.5.29(typescript@5.6.3) + '@vueuse/metadata': 14.4.0 + '@vueuse/shared': 14.4.0(vue@3.5.44(typescript@6.0.3)) + vue: 3.5.44(typescript@6.0.3) - '@vueuse/metadata@14.2.1': {} + '@vueuse/core@15.0.0(vue@3.5.44(typescript@6.0.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 15.0.0 + '@vueuse/shared': 15.0.0(vue@3.5.44(typescript@6.0.3)) + vue: 3.5.44(typescript@6.0.3) + + '@vueuse/metadata@14.4.0': {} + + '@vueuse/metadata@15.0.0': {} + + '@vueuse/shared@14.4.0(vue@3.5.44(typescript@6.0.3))': + dependencies: + vue: 3.5.44(typescript@6.0.3) - '@vueuse/shared@14.2.1(vue@3.5.29(typescript@5.6.3))': + '@vueuse/shared@15.0.0(vue@3.5.44(typescript@6.0.3))': dependencies: - vue: 3.5.29(typescript@5.6.3) + vue: 3.5.44(typescript@6.0.3) - alien-signals@1.0.13: {} + alien-signals@3.2.1: {} aria-hidden@1.2.6: dependencies: - tslib: 2.8.1 + tslib: 2.9.1 assertion-error@2.0.1: {} - balanced-match@1.0.2: {} - birpc@2.9.0: {} - brace-expansion@2.0.2: + buffer-image-size@0.6.4: dependencies: - balanced-match: 1.0.2 + '@types/node': 26.6.6 - chai@6.2.2: {} + chai@6.3.0: {} class-variance-authority@0.7.1: dependencies: @@ -2108,363 +1936,359 @@ snapshots: codemirror@6.0.2: dependencies: - '@codemirror/autocomplete': 6.20.1 - '@codemirror/commands': 6.10.2 - '@codemirror/language': 6.12.2 - '@codemirror/lint': 6.9.5 - '@codemirror/search': 6.6.0 - '@codemirror/state': 6.5.4 - '@codemirror/view': 6.39.16 + '@codemirror/autocomplete': 6.20.4 + '@codemirror/commands': 6.11.1 + '@codemirror/language': 6.13.1 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.2 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 - copy-anything@4.0.5: - dependencies: - is-what: 5.5.0 + copy-anything@4.1.5: {} - crelt@1.0.6: {} + crelt@1.0.7: {} csstype@3.2.3: {} - de-indent@1.0.2: {} - - defu@6.1.4: {} + defu@6.1.7: {} detect-libc@2.1.2: {} - enhanced-resolve@5.20.0: + enhanced-resolve@5.26.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.3 entities@7.0.1: {} - es-module-lexer@1.7.0: {} - - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 + es-module-lexer@2.3.2: {} estree-walker@2.0.2: {} estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.10 - expect-type@1.3.0: {} + expect-type@1.4.0: {} - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.7 fsevents@2.3.3: optional: true graceful-fs@4.2.11: {} - he@1.2.0: {} + happy-dom@21.0.4: + dependencies: + '@types/node': 26.6.6 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.2 + buffer-image-size: 0.6.4 + entities: 7.0.1 + whatwg-mimetype: 3.0.0 + ws: 8.22.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate hookable@5.5.3: {} - is-what@5.5.0: {} + jiti@2.7.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true - jiti@2.6.1: {} + lightningcss-darwin-x64@1.32.0: + optional: true - lightningcss-android-arm64@1.31.1: + lightningcss-darwin-x64@1.33.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-freebsd-x64@1.33.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss@1.31.1: + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 - - lucide-vue-next@0.563.0(vue@3.5.29(typescript@5.6.3)): - dependencies: - vue: 3.5.29(typescript@5.6.3) + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + 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 magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 - minimatch@9.0.9: + magic-string@1.4.5: dependencies: - brace-expansion: 2.0.2 + '@jridgewell/sourcemap-codec': 1.6.0 mitt@3.0.1: {} muggle-string@0.4.1: {} - nanoid@3.3.11: {} + nanoid@3.3.20: {} - obug@2.1.1: {} + nostics@1.3.0: {} - ohash@2.0.11: {} + obug@3.0.0: {} - path-browserify@1.0.1: {} + ohash@2.0.12: {} - pathe@2.0.3: {} + path-browserify@1.0.1: {} perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} + picocolors@1.1.1: {} - picomatch@4.0.3: {} + picomatch@4.0.7: {} - pinia@3.0.4(typescript@5.6.3)(vue@3.5.29(typescript@5.6.3)): + pinia@4.1.0(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.44(typescript@6.0.3)): dependencies: - '@vue/devtools-api': 7.7.9 - vue: 3.5.29(typescript@5.6.3) + '@vue/devtools-api': 8.2.1 + nostics: 1.3.0 + vue: 3.5.44(typescript@6.0.3) optionalDependencies: - typescript: 5.6.3 + typescript: 6.0.3 - postcss@8.5.6: + postcss@8.5.32: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 - reka-ui@2.8.2(vue@3.5.29(typescript@5.6.3)): + reka-ui@2.11.0(vue@3.5.44(typescript@6.0.3)): dependencies: - '@floating-ui/dom': 1.7.5 - '@floating-ui/vue': 1.1.10(vue@3.5.29(typescript@5.6.3)) - '@internationalized/date': 3.11.0 - '@internationalized/number': 3.6.5 - '@tanstack/vue-virtual': 3.13.21(vue@3.5.29(typescript@5.6.3)) - '@vueuse/core': 14.2.1(vue@3.5.29(typescript@5.6.3)) - '@vueuse/shared': 14.2.1(vue@3.5.29(typescript@5.6.3)) + '@floating-ui/vue': 2.0.1(vue@3.5.44(typescript@6.0.3)) + '@internationalized/date': 3.12.4 + '@internationalized/number': 3.6.9 + '@tanstack/vue-virtual': 3.13.51(vue@3.5.44(typescript@6.0.3)) + '@vueuse/core': 14.4.0(vue@3.5.44(typescript@6.0.3)) + '@vueuse/shared': 14.4.0(vue@3.5.44(typescript@6.0.3)) aria-hidden: 1.2.6 - defu: 6.1.4 - ohash: 2.0.11 - vue: 3.5.29(typescript@5.6.3) - transitivePeerDependencies: - - '@vue/composition-api' + defu: 6.1.7 + ohash: 2.0.12 + vue: 3.5.44(typescript@6.0.3) rfdc@1.4.1: {} - rollup@4.59.0: + rolldown@1.2.16: dependencies: - '@types/estree': 1.0.8 + '@oxc-project/types': 0.156.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 - fsevents: 2.3.3 - - siginfo@2.0.0: {} - - source-map-js@1.2.1: {} + '@rolldown/binding-android-arm-eabi': 1.2.16 + '@rolldown/binding-android-arm64': 1.2.16 + '@rolldown/binding-darwin-arm64': 1.2.16 + '@rolldown/binding-darwin-x64': 1.2.16 + '@rolldown/binding-freebsd-x64': 1.2.16 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.16 + '@rolldown/binding-linux-arm64-gnu': 1.2.16 + '@rolldown/binding-linux-arm64-musl': 1.2.16 + '@rolldown/binding-linux-ppc64-gnu': 1.2.16 + '@rolldown/binding-linux-s390x-gnu': 1.2.16 + '@rolldown/binding-linux-x64-gnu': 1.2.16 + '@rolldown/binding-linux-x64-musl': 1.2.16 + '@rolldown/binding-openharmony-arm64': 1.2.16 + '@rolldown/binding-win32-arm64-msvc': 1.2.16 + '@rolldown/binding-win32-x64-msvc': 1.2.16 + + source-map-js@1.2.2: {} speakingurl@14.0.1: {} - stackback@0.0.2: {} + std-env@4.3.0: {} - std-env@3.10.0: {} - - style-mod@4.1.3: {} + style-mod@4.1.4: {} superjson@2.2.6: dependencies: - copy-anything: 4.0.5 + copy-anything: 4.1.5 - tailwind-merge@3.5.0: {} + tailwind-merge@3.7.0: {} - tailwindcss@4.2.1: {} + tailwindcss@4.3.3: {} - tapable@2.3.0: {} + tapable@2.3.3: {} - tinybench@2.9.0: {} + tinybench@6.2.3: {} - tinyexec@1.0.2: {} + tinyexec@1.3.1: {} - tinyglobby@0.2.15: + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - tinyrainbow@3.0.3: {} + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 - tslib@2.8.1: {} + tslib@2.9.1: {} tw-animate-css@1.4.0: {} type-fest@4.41.0: {} - typescript@5.6.3: {} + typescript@6.0.3: {} - undici-types@7.18.2: {} + undici-types@8.9.0: {} - vee-validate@4.15.1(vue@3.5.29(typescript@5.6.3)): + vee-validate@4.15.1(vue@3.5.44(typescript@6.0.3)): dependencies: - '@vue/devtools-api': 7.7.9 + '@vue/devtools-api': 7.7.10 type-fest: 4.41.0 - vue: 3.5.29(typescript@5.6.3) + vue: 3.5.44(typescript@6.0.3) - vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1): + vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0): dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.32 + rolldown: 1.2.16 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.3.3 + '@types/node': 26.6.6 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.31.1 - - vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1) - why-is-node-running: 2.3.0 + jiti: 2.7.0 + + vitest@5.0.5(@types/node@26.6.6)(happy-dom@21.0.4)(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.5(vite@8.3.5(@types/node@26.6.6)(jiti@2.7.0)) + chai: 6.3.0 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.5 + obug: 3.0.0 + picomatch: 4.0.7 + std-env: 4.3.0 + tinybench: 6.2.3 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + vite: 8.3.5(@types/node@26.6.6)(jiti@2.7.0) + why-is-node-running: 3.2.1 optionalDependencies: - '@types/node': 25.3.3 + '@types/node': 26.6.6 + happy-dom: 21.0.4 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vscode-uri@3.1.0: {} + vscode-jsonrpc@10.0.0: {} - vue-demi@0.14.10(vue@3.5.29(typescript@5.6.3)): + vscode-languageserver-protocol@3.18.5: dependencies: - vue: 3.5.29(typescript@5.6.3) + vscode-jsonrpc: 10.0.0 + vscode-languageserver-types: 3.18.5 + + vscode-languageserver-textdocument@1.0.16: {} + + vscode-languageserver-types@3.18.5: {} + + vscode-uri@3.2.0: {} vue-sonner@2.0.9: {} - vue-tsc@2.2.12(typescript@5.6.3): + vue-tsc@3.3.14(typescript@6.0.3): dependencies: - '@volar/typescript': 2.4.15 - '@vue/language-core': 2.2.12(typescript@5.6.3) - typescript: 5.6.3 + '@volar/typescript': 2.4.30(typescript@6.0.3) + '@vue/language-core': 3.3.14 + typescript: 6.0.3 - vue@3.5.29(typescript@5.6.3): + vue@3.5.44(typescript@6.0.3): dependencies: - '@vue/compiler-dom': 3.5.29 - '@vue/compiler-sfc': 3.5.29 - '@vue/runtime-dom': 3.5.29 - '@vue/server-renderer': 3.5.29(vue@3.5.29(typescript@5.6.3)) - '@vue/shared': 3.5.29 + '@vue/compiler-dom': 3.5.44 + '@vue/compiler-sfc': 3.5.44 + '@vue/runtime-dom': 3.5.44 + '@vue/server-renderer': 3.5.44 + '@vue/shared': 3.5.44 optionalDependencies: - typescript: 5.6.3 + typescript: 6.0.3 w3c-keyname@2.2.8: {} - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 + whatwg-mimetype@3.0.0: {} + + why-is-node-running@3.2.1: {} + + ws@8.22.1: {} zod@3.25.76: {} diff --git a/src/components/AppSidebar.vue b/src/components/AppSidebar.vue index b6ddaee..9de99bb 100644 --- a/src/components/AppSidebar.vue +++ b/src/components/AppSidebar.vue @@ -3,7 +3,7 @@ import { ref, watch, computed } from 'vue'; import { SidebarProps, SidebarContent, SidebarGroup, Sidebar } from './ui/sidebar'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { Button } from "@/components/ui/button" -import { ChevronDown, Database, RefreshCcw, Loader2, ChevronUp, FileJson, LogOut } from 'lucide-vue-next'; +import { ChevronDown, Database, RefreshCcw, Loader2, ChevronUp, FileJson, LogOut } from '@lucide/vue'; import { ScrollArea } from '@/components/ui/scroll-area'; import { useConnectionStore } from '@/stores/connectionStore'; import { invoke } from '@tauri-apps/api/core'; diff --git a/src/components/Logo.vue b/src/components/Logo.vue index d861d11..dfa8f97 100644 --- a/src/components/Logo.vue +++ b/src/components/Logo.vue @@ -1,5 +1,5 @@ diff --git a/src/components/connection/ConnectionDialog.vue b/src/components/connection/ConnectionDialog.vue index c4a8cbc..31eb119 100644 --- a/src/components/connection/ConnectionDialog.vue +++ b/src/components/connection/ConnectionDialog.vue @@ -22,7 +22,7 @@ import { import Input from '@/components/ui/input/Input.vue'; import Button from '@/components/ui/button/Button.vue'; import TestStagesDisplay from './TestStagesDisplay.vue'; -import { Eye, EyeOff } from 'lucide-vue-next'; +import { Eye, EyeOff } from '@lucide/vue'; import { useConnectionStore } from '@/stores/connectionStore'; import { @@ -213,7 +213,7 @@ const everythingFilled = computed(() => { diff --git a/src/components/connection/ConnectionGrid.vue b/src/components/connection/ConnectionGrid.vue index b6f2b74..8554053 100644 --- a/src/components/connection/ConnectionGrid.vue +++ b/src/components/connection/ConnectionGrid.vue @@ -1,6 +1,6 @@ @@ -190,92 +188,116 @@ const everythingFilled = computed(() => { {{ dialogTitle }} {{ dialogDescription }} - -
- - - Connection Name - - + + + +
- - - Host - - + + + + + +
- - - - - + + +
- - - Username - - + + + + + + + + + +
- +

Connection Test

-
- + - - - diff --git a/src/components/ui/field/Field.vue b/src/components/ui/field/Field.vue new file mode 100644 index 0000000..5519d37 --- /dev/null +++ b/src/components/ui/field/Field.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/field/FieldContent.vue b/src/components/ui/field/FieldContent.vue new file mode 100644 index 0000000..d9a23fd --- /dev/null +++ b/src/components/ui/field/FieldContent.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/field/FieldDescription.vue b/src/components/ui/field/FieldDescription.vue new file mode 100644 index 0000000..7240a83 --- /dev/null +++ b/src/components/ui/field/FieldDescription.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/field/FieldError.vue b/src/components/ui/field/FieldError.vue new file mode 100644 index 0000000..fe2470c --- /dev/null +++ b/src/components/ui/field/FieldError.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/components/ui/field/FieldGroup.vue b/src/components/ui/field/FieldGroup.vue new file mode 100644 index 0000000..834d8ce --- /dev/null +++ b/src/components/ui/field/FieldGroup.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/field/FieldLabel.vue b/src/components/ui/field/FieldLabel.vue new file mode 100644 index 0000000..e2692ec --- /dev/null +++ b/src/components/ui/field/FieldLabel.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/components/ui/field/FieldLegend.vue b/src/components/ui/field/FieldLegend.vue new file mode 100644 index 0000000..c620fed --- /dev/null +++ b/src/components/ui/field/FieldLegend.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/field/FieldSeparator.vue b/src/components/ui/field/FieldSeparator.vue new file mode 100644 index 0000000..5bca4d5 --- /dev/null +++ b/src/components/ui/field/FieldSeparator.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/ui/field/FieldSet.vue b/src/components/ui/field/FieldSet.vue new file mode 100644 index 0000000..7be4dc9 --- /dev/null +++ b/src/components/ui/field/FieldSet.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/components/ui/field/FieldTitle.vue b/src/components/ui/field/FieldTitle.vue new file mode 100644 index 0000000..f564b8b --- /dev/null +++ b/src/components/ui/field/FieldTitle.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/field/index.ts b/src/components/ui/field/index.ts new file mode 100644 index 0000000..162ba14 --- /dev/null +++ b/src/components/ui/field/index.ts @@ -0,0 +1,39 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export const fieldVariants = cva( + "group/field flex w-full gap-3 data-[invalid=true]:text-destructive", + { + variants: { + orientation: { + vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"], + horizontal: [ + "flex-row items-center", + "[&>[data-slot=field-label]]:flex-auto", + "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + responsive: [ + "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto", + "@md/field-group:[&>[data-slot=field-label]]:flex-auto", + "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + }, + }, + defaultVariants: { + orientation: "vertical", + }, + }, +) + +export type FieldVariants = VariantProps + +export { default as Field } from "./Field.vue" +export { default as FieldContent } from "./FieldContent.vue" +export { default as FieldDescription } from "./FieldDescription.vue" +export { default as FieldError } from "./FieldError.vue" +export { default as FieldGroup } from "./FieldGroup.vue" +export { default as FieldLabel } from "./FieldLabel.vue" +export { default as FieldLegend } from "./FieldLegend.vue" +export { default as FieldSeparator } from "./FieldSeparator.vue" +export { default as FieldSet } from "./FieldSet.vue" +export { default as FieldTitle } from "./FieldTitle.vue" diff --git a/src/components/ui/form/FormControl.vue b/src/components/ui/form/FormControl.vue deleted file mode 100644 index b1bc4bf..0000000 --- a/src/components/ui/form/FormControl.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/src/components/ui/form/FormDescription.vue b/src/components/ui/form/FormDescription.vue deleted file mode 100644 index 2d3a903..0000000 --- a/src/components/ui/form/FormDescription.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - diff --git a/src/components/ui/form/FormItem.vue b/src/components/ui/form/FormItem.vue deleted file mode 100644 index 40cb994..0000000 --- a/src/components/ui/form/FormItem.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/src/components/ui/form/FormLabel.vue b/src/components/ui/form/FormLabel.vue deleted file mode 100644 index 141655b..0000000 --- a/src/components/ui/form/FormLabel.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/src/components/ui/form/FormMessage.vue b/src/components/ui/form/FormMessage.vue deleted file mode 100644 index c80c482..0000000 --- a/src/components/ui/form/FormMessage.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/src/components/ui/form/index.ts b/src/components/ui/form/index.ts deleted file mode 100644 index 1eb05f1..0000000 --- a/src/components/ui/form/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { default as FormControl } from "./FormControl.vue" -export { default as FormDescription } from "./FormDescription.vue" -export { default as FormItem } from "./FormItem.vue" -export { default as FormLabel } from "./FormLabel.vue" -export { default as FormMessage } from "./FormMessage.vue" -export { FORM_ITEM_INJECTION_KEY } from "./injectionKeys" -export { Form, Field as FormField, FieldArray as FormFieldArray } from "vee-validate" diff --git a/src/components/ui/form/injectionKeys.ts b/src/components/ui/form/injectionKeys.ts deleted file mode 100644 index 42542a9..0000000 --- a/src/components/ui/form/injectionKeys.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { InjectionKey } from "vue" - -export const FORM_ITEM_INJECTION_KEY - = Symbol() as InjectionKey diff --git a/src/components/ui/form/useFormField.ts b/src/components/ui/form/useFormField.ts deleted file mode 100644 index 62d86c2..0000000 --- a/src/components/ui/form/useFormField.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { FieldContextKey } from "vee-validate" -import { computed, inject } from "vue" -import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys" - -export function useFormField() { - const fieldContext = inject(FieldContextKey) - const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY) - - if (!fieldContext) - throw new Error("useFormField should be used within ") - - const { name, errorMessage: error, meta } = fieldContext - const id = fieldItemContext - - const fieldState = { - valid: computed(() => meta.valid), - isDirty: computed(() => meta.dirty), - isTouched: computed(() => meta.touched), - error, - } - - return { - id, - name, - formItemId: `${id}-form-item`, - formDescriptionId: `${id}-form-item-description`, - formMessageId: `${id}-form-item-message`, - ...fieldState, - } -} From 955c08f44ab297f7e829e47e65e15eff4d988f7a Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:43:51 +0100 Subject: [PATCH 07/33] chore: update rust crates every crate to its latest stable release: tauri 2.12 with its plugins (matching @tauri-apps/api 2.12 on the npm side; tauri 3 is an alpha), mongodb 3.9, tokio, uuid, thiserror, log, futures. bson stays 2.15, which mongodb 3.x still uses by default. keyring 4 moved its credential stores into crates of their own; its default v1 mode keeps the api of keyring 3 and uses keychain, the windows credential manager and the secret service. on linux that drops the keyutils cache and the vendored openssl of keyring 3. passwords saved with keyring 3 stay readable: a check program read the three stored passwords on the development machine with both versions. the build needed tauri's linux packages, which were not installed on the development machine: the earlier cargo check only reused build results from march. the docs said it passed; they now say what was checked and name the packages for ubuntu 26.04, including libdbus, which tao links since tauri 2.12 and keyring 3's vendored feature used to build from source. checked: cargo check without warnings. cargo clippy reports 15 warnings, all in code that predates the update (it could not compile before). --- CLAUDE.md | 5 +- docs/architecture/decisions.md | 1 + docs/architecture/overview.md | 10 +- docs/features/credential-storage.md | 5 +- src-tauri/Cargo.lock | 3198 ++++++++++++--------------- src-tauri/Cargo.toml | 16 +- 6 files changed, 1411 insertions(+), 1824 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5ba6a4a..2523909 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,7 +33,7 @@ cd src-tauri && cargo test # no Rust tests exist yet cd src-tauri && cargo clippy ``` -Needs Rust and the Tauri prerequisites (`README.md`). For a manual check run a local MongoDB, e.g. `docker run --rm -p 27017:27017 mongo:8`, and connect to `localhost:27017` without authentication. +Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev`. Without them no Rust code compiles, but an old `target/` can make `cargo check` look fine. For a manual check run a local MongoDB, e.g. `docker run --rm -p 27017:27017 mongo:8`, and connect to `localhost:27017` without authentication. ## Architecture @@ -107,7 +107,8 @@ Needs Rust and the Tauri prerequisites (`README.md`). For a manual check run a l - Commands reach the keyring by downcasting the repository to `FileRepository`. Another repository type fails with "Unsupported repository type". - The log level is `Debug` in release builds too. `ConnectionDialog` logs form values, password included, at `trace`. - Query filters cross IPC as extended JSON. bson turns `{ $oid }`, `{ $date: "" }` and the number wrappers into BSON types; anything it can't read stays a plain object and silently matches nothing. -- On Linux the keyring needs a Secret Service (GNOME Keyring, KWallet). `keyring` is built with `vendored`, which compiles OpenSSL. +- On Linux the keyring needs a Secret Service (GNOME Keyring, KWallet). keyring 4 talks to it through `zbus`; there is no keyutils cache any more. +- `cargo clippy` reports 15 warnings in code that predates the revival (needless borrows, missing `Default`, an 8-argument command, …). Fix them where you touch the code. - Change the pinned pnpm with `pnpm self-update ` inside the repo, never by hand, or `--frozen-lockfile` fails (pnpm records its version in the lockfile). - `gh` is not installed on this machine. The repo is public: read issues and pull requests through `https://api.github.com/repos/WebXIO/monolens/issues` and `/pulls`. diff --git a/docs/architecture/decisions.md b/docs/architecture/decisions.md index 7ad3e7a..b745294 100644 --- a/docs/architecture/decisions.md +++ b/docs/architecture/decisions.md @@ -21,6 +21,7 @@ This log was written on 2026-11-03 from the commit history, the pull requests an | 2026-02-20 | Testing a connection is optional; a connection can be saved untested (`963da88`, issue #26) | The issue gives no reason | Requiring a successful test before saving | | 2026-02-18 | Credentials stay in Rust. `get_connections` and `get_connection` never return a password, the commands that connect load it from the keyring themselves (`00b3284`, `84839a6`, PR #23, issue #24) | Passwords should not be exposed to the web view, and the grid shouldn't hit the keyring for every connection | Hydrating passwords when listing (the first version) | | 2026-02-18 | Connections are stored as a versioned JSON object keyed by id: `{ "version": 1, "connections": { … } }` (`84839a6`, issue #24) | O(1) access by id, and a version to migrate the file when its shape changes | A plain array of connections (the first version) | +| 2026-11-03 | keyring 4 with its default `v1` mode: Keychain, Credential Manager, Secret Service. Reverses the keyutils cache of `aad2e90` | All packages were updated. keyring 4 moved its stores into separate crates; `v1` keeps the API. Passwords saved with keyring 3 stay readable (checked) | `keyring-core` with chosen store crates (keyutils plus Secret Service as before), staying on keyring 3.6 | | 2026-02-18 | On Linux the keyring uses `linux-native-sync-persistent` with `vendored` (`aad2e90`) | keyutils for fast kernel-level access during a session, Secret Service for persistence. `vendored` bundles OpenSSL, which the keyring needs on Linux | `sync-secret-service` alone (the first setting) | | 2026-02-17 | Passwords are stored in the OS keyring through the `keyring` crate (`eb8fdd9`, issue #15) | Uses the native store on Windows, macOS and Linux | Tauri Stronghold: added on 2026-02-15 (`8b54cd3`) and reverted on 2026-02-17 (`02a2c3a`). The revert says only that Stronghold "is not needed anymore" | | 2026-02-15 | The password is set on the URL with `Url::set_password`, which percent-encodes it (`8a9638a`, issue #21) | Passwords with special characters failed with "password must be URL encoded" | | diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index e70cd22..e2a0d82 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -31,7 +31,7 @@ This file describes `develop` as of 2026-11-03 (`859c252`). `main` is at `efee3a | Part | Technology | Path | |---|---|---| -| Rust core | Tauri 2.10, tokio, `mongodb` 3.5 (bson 2.15), `keyring` 3.6, `thiserror`, `tauri-plugin-log`, `tauri-plugin-opener` | `src-tauri/src` | +| Rust core | Tauri 2.12, tokio, `mongodb` 3.9 (bson 2.15), `keyring` 4.2, `thiserror`, `tauri-plugin-log`, `tauri-plugin-opener` | `src-tauri/src` | | UI | Vue 3.5, Pinia 4, Tailwind 4 with shadcn-vue components on reka-ui, TanStack Form + zod 4, vue-sonner, lucide icons (`@lucide/vue`) | `src` | | Query editor and JSON view | CodeMirror 6 (`@codemirror/lang-json`, `theme-one-dark`, `autocomplete`) | `src/components/query`, `src/components/documents/json` | | Table view | TanStack Table 9 and TanStack Virtual 3 | `src/components/documents/table`, `src/composables/table` | @@ -136,13 +136,13 @@ pnpm build # vue-tsc --noEmit, then vite build (also the beforeBuil pnpm tauri build # installers for the current platform ``` -Rust and the Tauri prerequisites must be installed (see the root README). `7ee4b70` (2026-02-15) notes that the build worked for deb, rpm and AppImage. +Rust and the Tauri prerequisites must be installed (see the root README). On Ubuntu 26.04 that is `sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev`; webkit brings `libdbus-1-dev`, which `tao` needs since Tauri 2.12. `7ee4b70` (2026-02-15) notes that the build worked for deb, rpm and AppImage. -Checked on 2026-11-03 on `develop`, Node 24.9, pnpm 11.3, Rust 1.93: +Checked on 2026-11-03 on `develop` (`859c252`), Node 24.9, pnpm 11.3, Rust 1.93: - `pnpm test:frontend --run`: 3 files, 27 tests pass. -- `cargo check`: passes without warnings. -- `pnpm build` fails: `src/utils/queryParser/test/tokens.test.ts(3,1): error TS6133: 'T' is declared but its value is never read.` The tsconfig includes the test files and sets `noUnusedLocals`. `vite build` alone passes. So `pnpm tauri build` fails too until the import is removed. +- `cargo check` seemed to pass, but only reused build results from March: the Tauri prerequisites were not installed on the machine, and no Rust code compiled. With them installed, it passes; `cargo clippy` has 15 warnings. +- `pnpm build` fails: `src/utils/queryParser/test/tokens.test.ts(3,1): error TS6133: 'T' is declared but its value is never read.` The tsconfig includes the test files and sets `noUnusedLocals`. `vite build` alone passes. So `pnpm tauri build` fails too until the import is removed (fixed in `c25ace4`). - There are no Rust tests and no CI. ## Branches diff --git a/docs/features/credential-storage.md b/docs/features/credential-storage.md index b5395f7..7fd27e7 100644 --- a/docs/features/credential-storage.md +++ b/docs/features/credential-storage.md @@ -7,7 +7,7 @@ Passwords of saved connections must not sit in a plain file. Monolens keeps them ## How it works - `CredentialService` wraps `keyring::Entry`. The service name is `monolens-connections` and the entry is `connection::basic_password`. Set, get and delete run in `spawn_blocking`, because the keyring calls block. -- The `keyring` crate uses the native store of each platform (features `apple-native`, `windows-native`, `linux-native-sync-persistent`, `vendored`). On Linux it combines keyutils, fast and kernel-level for the session, with the Secret Service for persistence. `vendored` bundles the OpenSSL that the Linux backend needs. +- The `keyring` crate (4.x, its default `v1` mode) uses the native store of each platform: Keychain on macOS, the Credential Manager on Windows, the Secret Service on Linux (through `zbus`, pure Rust, no OpenSSL). - Writing: - `create_connection` takes the password out of the request, writes it to the keyring under the new id, and saves the connection without it. - `update_connection` writes the password for `BASIC` when one is sent, and deletes the entry for `NONE`. The file never gets the password. @@ -26,7 +26,7 @@ Passwords of saved connections must not sit in a plain file. Monolens keeps them ## Decisions - **OS keyring through `keyring`** (`eb8fdd9`, issue #15). Tauri Stronghold was added on 2026-02-15 (`8b54cd3`) and reverted two days later (`02a2c3a`). The revert says only that Stronghold "is not needed anymore". -- **Linux: keyutils plus Secret Service, OpenSSL vendored** (`aad2e90`). Fast access during a session, persistence across sessions, no system OpenSSL needed. +- **Linux: keyutils plus Secret Service, OpenSSL vendored** (`aad2e90`), replaced on 2026-11-03 by keyring 4, which only uses the Secret Service. Passwords saved with keyring 3 are read by keyring 4 unchanged (checked with the three connections on the development machine). - **Passwords stay in Rust** (`00b3284`, `84839a6`, PR #23). Listing doesn't touch the keyring, and only the commands that connect load a password. - **Exception: the edit dialog shows the password** (`dc020e7`, issue #29). Users wanted to see what they saved. It is fetched only when the dialog opens. - **Percent-encoding through `Url`** (`8a9638a`, issue #21). Passwords with special characters broke the connection string. @@ -43,6 +43,7 @@ Passwords of saved connections must not sit in a plain file. Monolens keeps them | 2026-02-18 | Password loaded only on connect, never returned when listing | `00b3284`, `84839a6` | | 2026-02-20 | The edit dialog shows the stored password | `dc020e7` | | 2026-02-22 | Credentials removed from logs, URI logged only in debug builds | `8d6bcac` | +| 2026-11-03 | keyring 4: the Secret Service alone on Linux, no keyutils cache, no OpenSSL | `chore: update rust crates` | ## Limits and open points diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index d0f68bf..b8a6f0d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -9,14 +9,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] -name = "ahash" -version = "0.7.8" +name = "aes" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "fc0fc36d7440d015b45468ba08a21e80e056ebbd014c611c6298bb7503e04bd1" dependencies = [ - "getrandom 0.2.17", - "once_cell", - "version_check", + "cipher", + "cpubits", + "cpufeatures 0.3.1", ] [[package]] @@ -34,24 +34,24 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] [[package]] name = "alloc-no-stdlib" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" +checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1" dependencies = [ "alloc-no-stdlib", ] @@ -75,24 +75,29 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] -name = "arrayvec" -version = "0.7.6" +name = "apple-native-keyring-store" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "2b350bfd03649e07aa05c0a81b3e15934374e585c98204a57e20b9d49f49bb9a" +dependencies = [ + "keyring-core", + "log", + "security-framework", +] [[package]] name = "async-broadcast" @@ -120,9 +125,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +checksum = "f426a31126c735126297bc5ea7a521263c9faff4f63ca415267ee625651c4f37" dependencies = [ "async-task", "concurrent-queue", @@ -152,9 +157,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.2" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +checksum = "0876700b0d007ad25d5508865a4259c3af9af6d296bf663a0d586d0bc3369f6f" dependencies = [ "event-listener", "event-listener-strategy", @@ -181,20 +186,20 @@ dependencies = [ [[package]] name = "async-recursion" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +checksum = "4f8abc12baad266b1c8cec146854c195b5864b4221d4b2ca7296a7ae82d9e451" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", @@ -216,13 +221,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -256,9 +261,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64" @@ -272,6 +277,27 @@ 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", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -280,18 +306,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" dependencies = [ "serde_core", ] [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -309,55 +335,50 @@ dependencies = [ ] [[package]] -name = "block2" -version = "0.6.2" +name = "block-buffer" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "objc2", + "hybrid-array", ] [[package]] -name = "blocking" -version = "1.6.2" +name = "block-padding" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", + "hybrid-array", ] [[package]] -name = "borsh" -version = "1.6.0" +name = "block2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "borsh-derive", - "cfg_aliases", + "objc2", ] [[package]] -name = "borsh-derive" -version = "1.6.0" +name = "blocking" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa" dependencies = [ - "once_cell", - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.117", + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", ] [[package]] name = "brotli" -version = "8.0.2" +version = "9.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "627b7cfb0578f0eafce087a90fcd40add1231900b69e4d4de2d456260a4f5d81" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -366,30 +387,39 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "34c6783f42c21c952ad7112b354f0ba2f10760e9decea5b1b60523d6e270faaf" 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 = "bson" version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e" dependencies = [ - "ahash 0.8.12", + "ahash", "base64 0.22.1", "bitvec", "getrandom 0.2.17", "getrandom 0.3.4", "hex", - "indexmap 2.13.0", + "indexmap 2.14.2", "js-sys", "once_cell", - "rand 0.9.2", + "rand 0.9.5", "serde", "serde_bytes", "serde_json", @@ -399,49 +429,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byte-unit" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" -dependencies = [ - "rust_decimal", - "schemars 1.2.1", - "serde", - "utf8-width", -] - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -451,9 +447,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] @@ -464,7 +460,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cairo-sys-rs", "glib", "libc", @@ -485,9 +481,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.2" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591" dependencies = [ "serde_core", ] @@ -512,24 +508,34 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "cargo_toml" -version = "0.22.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9" dependencies = [ + "semver", "serde", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", +] + +[[package]] +name = "cbc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" +dependencies = [ + "cipher", ] [[package]] name = "cc" -version = "1.2.56" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "375989decec1a0fa424442bed520fa12ede43a48475ce8c7417d2c69b32b5f6b" dependencies = [ "find-msvc-tools", "shlex", @@ -543,13 +549,13 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfb" -version = "0.7.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" dependencies = [ - "byteorder", "fnv", "uuid", + "web-time", ] [[package]] @@ -564,33 +570,54 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "chacha20" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link 0.2.1", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "crypto-common 0.2.2", + "inout", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "combine" -version = "4.6.7" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" dependencies = [ "bytes", "memchr", @@ -605,6 +632,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const-random" version = "0.1.18" @@ -625,12 +658,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.10.0" @@ -642,9 +669,9 @@ dependencies = [ [[package]] name = "cookie" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" dependencies = [ "time", "version_check", @@ -678,14 +705,14 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "libc", ] @@ -695,11 +722,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "libc", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -709,11 +742,20 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "5f97d3416d5337d15c4b0d78c8c91df922ca143f57ec20e2d1c188333047ef04" dependencies = [ "cfg-if", ] @@ -726,27 +768,27 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -764,48 +806,58 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cssparser" -version = "0.29.6" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", + "phf", "smallvec", - "syn 1.0.109", ] [[package]] name = "cssparser-macros" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a" dependencies = [ "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "ctor" -version = "0.2.9" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d" + +[[package]] +name = "ctutils" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "261af4dc7a06ea8a527a8717d8cbba3417530d6ea14e1edb3de6b67806be474f" dependencies = [ - "quote", - "syn 2.0.117", + "cmov", ] [[package]] name = "darling" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ "darling_core", "darling_macro", @@ -813,64 +865,82 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "dbus" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" dependencies = [ "libc", "libdbus-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] -name = "dbus-secret-service" -version = "4.1.0" +name = "defmt" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" +checksum = "e4a0795ac740cb54d7b3775c9c17345f6aaecf884c01733b39d6017738e0e3e1" dependencies = [ - "dbus", - "openssl", - "zeroize", + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840bb056bd99c495c9188198a258ab787c79f306d864db3e6e8451442d6d8366" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "defmt-parser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71958f69fb2de856c5dd51ac9377e986ca1aa5919f931bf5395a807277f889a0" +dependencies = [ + "thiserror 2.0.21", ] [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" dependencies = [ - "powerfmt", "serde_core", ] @@ -882,31 +952,18 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "derive-where" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "derive_more" -version = "0.99.20" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "2e2b94854e8576378ccda7c8de8a66ed8b4e8acbd2c50ec3418ea6c8aaf4b567" dependencies = [ - "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -924,11 +981,11 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case 0.10.0", + "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn 2.0.119", "unicode-xid", ] @@ -938,16 +995,27 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", - "subtle", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", + "ctutils", ] [[package]] name = "dirs" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" dependencies = [ "dirs-sys", ] @@ -964,31 +1032,27 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - [[package]] name = "dispatch2" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", + "block2", + "libc", "objc2", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -1011,7 +1075,22 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", +] + +[[package]] +name = "dom_query" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", ] [[package]] @@ -1050,18 +1129,24 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" + [[package]] name = "embed-resource" -version = "3.0.6" +version = "3.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" +checksum = "6168487b5e7eb2673e6efe1200b1848016e436a6ca0b8031bf04bd9d493a249f" dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", "vswhom", - "winreg 0.55.0", + "winreg", ] [[package]] @@ -1076,18 +1161,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "enumflags2" version = "0.7.12" @@ -1106,7 +1179,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1121,15 +1194,15 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "1e59b668157f32d3459d4bd634861a06ffa2503a461ca5f0916b9f0252605e66" dependencies = [ "serde", "serde_core", @@ -1148,11 +1221,10 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -1169,9 +1241,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fdeflate" @@ -1203,18 +1275,19 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.9.1", + "zlib-rs", ] [[package]] @@ -1225,18 +1298,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "foreign-types" @@ -1245,26 +1309,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] -[[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" @@ -1286,21 +1344,11 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -1313,9 +1361,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -1323,15 +1371,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -1340,9 +1388,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-lite" @@ -1359,32 +1407,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-channel", "futures-core", @@ -1397,15 +1445,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" version = "0.18.2" @@ -1515,17 +1554,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -1535,7 +1563,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1548,22 +1576,21 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasip2", - "wasip3", + "r-efi 6.0.0", + "rand_core 0.10.1", ] [[package]] @@ -1604,7 +1631,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "futures-channel", "futures-core", "futures-executor", @@ -1632,7 +1659,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1647,9 +1674,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "gobject-sys" @@ -1711,7 +1738,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1719,24 +1746,12 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -1752,9 +1767,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "hex" @@ -1763,77 +1778,108 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-proto" -version = "0.25.2" +name = "hickory-net" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "c480823ed7c2c5d0f09c41020cb6b7c28029ce60ec42dc942158dcf22f8e0a4d" dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", + "hickory-proto", + "idna", + "ipnet", + "jni 0.22.4", + "rand 0.10.3", + "thiserror 2.0.21", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-proto" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b92608f679a6fa515dd1d15c1ff89443026e391200a2c840c7afcba482893d" +dependencies = [ + "data-encoding", "idna", "ipnet", + "jni 0.22.4", "once_cell", - "rand 0.9.2", + "prefix-trie", + "rand 0.10.3", "ring", - "thiserror 2.0.18", + "thiserror 2.0.21", "tinyvec", - "tokio", "tracing", "url", ] [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "3f3da5255c95d5a716857d54b5b8f4e8d67c3484d3beaaaae2ce25063b3ba981" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni 0.22.4", "moka", + "ndk-context", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.10.3", "resolv-conf", "smallvec", - "thiserror 2.0.18", + "system-configuration", + "thiserror 2.0.21", "tokio", "tracing", ] +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest", + "digest 0.11.3", ] [[package]] name = "html5ever" -version = "0.29.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ "log", - "mac", "markup5ever", - "match_token", ] [[package]] name = "http" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -1841,9 +1887,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -1851,9 +1897,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1868,22 +1914,29 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c" dependencies = [ "atomic-waker", "bytes", - "futures-channel", "futures-core", "http", "http-body", "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1891,22 +1944,23 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "bytes", "futures-channel", "futures-util", "http", "http-body", + "httparse", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2", "tokio", "tower-service", "tracing", @@ -1924,7 +1978,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -1938,9 +1992,9 @@ dependencies = [ [[package]] name = "ico" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +checksum = "d75e94d66081e4d8dcd098bd8dc5254800fea14a26389b298410158d834de167" dependencies = [ "byteorder", "png", @@ -1948,12 +2002,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1961,9 +2016,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", @@ -1974,9 +2029,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1988,16 +2043,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -2008,15 +2064,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", @@ -2027,12 +2083,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -2052,9 +2102,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -2073,50 +2123,54 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] [[package]] name = "infer" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4" dependencies = [ "cfb", ] [[package]] -name = "ipconfig" -version = "0.3.2" +name = "inout" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "3b5cf4372d022092674a83b8febf5865f7a573cc0c5baec5e49c879b6a20978f" dependencies = [ - "socket2 0.5.10", - "widestring", - "windows-sys 0.48.0", - "winreg 0.50.0", + "block-padding", + "hybrid-array", ] [[package]] -name = "ipnet" -version = "2.11.0" +name = "ipconfig" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" +dependencies = [ + "socket2", + "widestring", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", +] [[package]] -name = "iri-string" -version = "0.7.10" +name = "ipnet" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" dependencies = [ - "memchr", "serde", ] @@ -2141,9 +2195,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "javascriptcore-rs" @@ -2168,6 +2222,60 @@ dependencies = [ "system-deps", ] +[[package]] +name = "jiff" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ac703058abac89e5c39b0b879dce2b6b14a4ba36600c7e7e3d0c60a6883ef3c" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aee43309eb53bafb8c36d35d6e444769c8f8e6206a9fbf7546f5db9d7d4a0e93" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc32470c67eb7d0e9ccb74303fa925313dc04cecb1aa048beaa6f391e36a93d" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" + +[[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" @@ -2177,46 +2285,99 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.21", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + [[package]] name = "jni-sys" -version = "0.3.0" +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 = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "3.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.21", ] [[package]] name = "jsonptr" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" dependencies = [ "serde", "serde_json", @@ -2224,56 +2385,35 @@ dependencies = [ [[package]] name = "keyboard-types" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "serde", - "unicode-segmentation", ] [[package]] name = "keyring" -version = "3.6.3" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" +checksum = "2270074a3d26bcac93c1dc5d2845eb4c089e8d761ccf6e0ea266a16004640627" dependencies = [ - "byteorder", - "dbus-secret-service", - "linux-keyutils", - "log", - "openssl", - "security-framework 2.11.1", - "security-framework 3.7.0", - "windows-sys 0.60.2", - "zeroize", + "apple-native-keyring-store", + "keyring-core", + "windows-native-keyring-store", + "zbus-secret-service-keyring-store", ] [[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" +name = "keyring-core" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" +checksum = "29fbf4b551298c67925f38cf341a1ada797a75f1837bdf8ae1fc8e2ebc6efb59" dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.13.0", - "selectors", + "log", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libappindicator" version = "0.9.0" @@ -2300,9 +2440,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.182" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "libdbus-sys" @@ -2310,7 +2450,6 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" dependencies = [ - "cc", "pkg-config", ] @@ -2326,20 +2465,10 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" -dependencies = [ - "libc", -] - -[[package]] -name = "linux-keyutils" -version = "0.2.4" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ - "bitflags 2.11.0", "libc", ] @@ -2351,9 +2480,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "lock_api" @@ -2366,18 +2495,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -dependencies = [ - "value-bag", -] - -[[package]] -name = "mac" -version = "0.1.1" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c" [[package]] name = "macro_magic" @@ -2388,7 +2508,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2402,7 +2522,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2413,7 +2533,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2424,55 +2544,35 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "markup5ever" -version = "0.14.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", ] -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "md-5" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest", + "digest 0.11.3", ] [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memoffset" @@ -2499,22 +2599,32 @@ dependencies = [ "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.1.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.61.2", ] [[package]] name = "moka" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b" +checksum = "4293f18e7567a1caf3c584855554377025c65e0aa445344d04171f5ad63d19b9" dependencies = [ "crossbeam-channel", "crossbeam-epoch", @@ -2529,9 +2639,9 @@ dependencies = [ [[package]] name = "mongocrypt" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da0cd419a51a5fb44819e290fbdb0665a54f21dead8923446a799c7f4d26ad9" +checksum = "8426a875ded61430d4a811dbfda7633b6b8af0225c547fc6c28b8b0aa7d79a13" dependencies = [ "bson", "mongocrypt-sys", @@ -2541,25 +2651,26 @@ dependencies = [ [[package]] name = "mongocrypt-sys" -version = "0.1.5+1.15.1" +version = "0.1.6+1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224484c5d09285a7b8cb0a0c117e847ebd14cb6e4470ecf68cdb89c503b0edb9" +checksum = "851fac73f7fe22f6a3ab87f720ce509cae7c9fd08e7dd27866cc232dee07ccf4" [[package]] name = "mongodb" -version = "3.5.1" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "803dd859e8afa084c255a8effd8000ff86f7c8076a50cd6d8c99e8f3496f75c2" +checksum = "af84443ae9878f59a6818686f339064479f42cdf293c4c637d8fc9c0a8c5eed6" dependencies = [ "base64 0.22.1", - "bitflags 2.11.0", + "bitflags 2.13.2", "bson", "derive-where", - "derive_more 2.1.1", + "derive_more", "futures-core", "futures-io", "futures-util", "hex", + "hickory-net", "hickory-proto", "hickory-resolver", "hmac", @@ -2569,20 +2680,19 @@ dependencies = [ "mongodb-internal-macros", "pbkdf2", "percent-encoding", - "rand 0.9.2", + "rand 0.9.5", "rustc_version_runtime", "rustls", - "rustversion", "serde", "serde_bytes", "serde_with", "sha1", - "sha2", - "socket2 0.6.2", + "sha2 0.11.1", + "socket2", "stringprep", "strsim", "take_mut", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "tokio-rustls", "tokio-util", @@ -2593,14 +2703,14 @@ dependencies = [ [[package]] name = "mongodb-internal-macros" -version = "3.5.1" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973ef3dd3dbc6f6e65bbdecfd9ec5e781b9e7493b0f369a7c62e35d8e5ae2c8" +checksum = "504024bbb83ab1bf1512007f7288b54d3a6343043f3f619c26a153346773598d" dependencies = [ "macro_magic", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2618,7 +2728,7 @@ dependencies = [ "tauri-build", "tauri-plugin-log", "tauri-plugin-opener", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "url", "uuid", @@ -2626,9 +2736,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.17.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996" dependencies = [ "crossbeam-channel", "dpi", @@ -2641,8 +2751,8 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.18", - "windows-sys 0.60.2", + "thiserror 2.0.21", + "windows-sys 0.61.2", ] [[package]] @@ -2651,8 +2761,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.0", - "jni-sys", + "bitflags 2.13.2", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -2672,7 +2782,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -2682,62 +2792,119 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-conv" -version = "0.2.0" +name = "num" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] [[package]] -name = "num-traits" -version = "0.2.19" +name = "num-bigint" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ - "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "num_enum" -version = "0.7.5" +name = "num-complex" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ - "num_enum_derive", - "rustversion", + "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-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "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.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "num_threads" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +checksum = "cabcc654086861f9e1bc5115258de62ef92c79b20f4615a1b0cc57c4e82027d4" dependencies = [ "libc", ] [[package]] name = "objc2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8" dependencies = [ "objc2-encode", "objc2-exception-helper", @@ -2749,17 +2916,10 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", - "libc", "objc2", - "objc2-cloud-kit", - "objc2-core-data", "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-core-text", - "objc2-core-video", "objc2-foundation", "objc2-quartz-core", ] @@ -2770,7 +2930,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2", "objc2-foundation", ] @@ -2781,7 +2941,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "bitflags 2.11.0", "objc2", "objc2-foundation", ] @@ -2792,7 +2951,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dispatch2", "objc2", ] @@ -2803,7 +2962,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dispatch2", "objc2", "objc2-core-foundation", @@ -2821,28 +2980,25 @@ dependencies = [ ] [[package]] -name = "objc2-core-text" +name = "objc2-core-location" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" dependencies = [ - "bitflags 2.11.0", "objc2", - "objc2-core-foundation", - "objc2-core-graphics", + "objc2-foundation", ] [[package]] -name = "objc2-core-video" +name = "objc2-core-text" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-io-surface", ] [[package]] @@ -2866,9 +3022,8 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", - "libc", "objc2", "objc2-core-foundation", ] @@ -2879,17 +3034,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-javascript-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" -dependencies = [ + "bitflags 2.13.2", "objc2", "objc2-core-foundation", ] @@ -2900,32 +3045,40 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2", "objc2-core-foundation", "objc2-foundation", ] [[package]] -name = "objc2-security" +name = "objc2-ui-kit" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.0", + "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-ui-kit" +name = "objc2-user-notifications" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ - "bitflags 2.11.0", "objc2", - "objc2-core-foundation", "objc2-foundation", ] @@ -2935,21 +3088,19 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", - "objc2-javascript-core", - "objc2-security", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" dependencies = [ "critical-section", "portable-atomic", @@ -2957,62 +3108,13 @@ dependencies = [ [[package]] name = "open" -version = "5.3.3" +version = "5.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "8d8c8b8e725ad26404d6896eb2f064294a0a7b4f1d9120210d85544684c4ca95" dependencies = [ "dunce", "is-wsl", "libc", - "pathdiff", -] - -[[package]] -name = "openssl" -version = "0.10.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" -dependencies = [ - "bitflags 2.11.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "openssl-src" -version = "300.5.5+3.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", ] [[package]] @@ -3082,22 +3184,16 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link 0.2.1", + "windows-link", ] -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "pbkdf2" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" dependencies = [ - "digest", + "digest 0.11.3", ] [[package]] @@ -3108,136 +3204,55 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_macros", + "phf_shared", + "serde", ] [[package]] name = "phf_codegen" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", ] [[package]] name = "phf_generator" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", + "fastrand", + "phf_shared", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", + "syn 2.0.119", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.2", + "siphasher", ] [[package]] @@ -3246,12 +3261,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.5" @@ -3265,18 +3274,18 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plist" -version = "1.8.0" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +checksum = "327a4cb2ad49dc48adfdc9da89e22c64d488b508c67a044d71ba729e4521a285" dependencies = [ - "base64 0.22.1", - "indexmap 2.13.0", + "base64 0.23.1", + "indexmap 2.14.2", "quick-xml", "serde", "time", @@ -3284,15 +3293,15 @@ dependencies = [ [[package]] name = "png" -version = "0.17.16" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.13.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.9", ] [[package]] @@ -3311,24 +3320,33 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +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.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] [[package]] name = "powerfmt" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" [[package]] name = "ppv-lite86" @@ -3346,13 +3364,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] -name = "prettyplease" -version = "0.2.37" +name = "prefix-trie" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" dependencies = [ - "proc-macro2", - "syn 2.0.117", + "either", + "ipnet", + "num-traits", ] [[package]] @@ -3377,11 +3396,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.10+spec-1.0.0", + "toml_edit 0.25.17+spec-1.1.0", ] [[package]] @@ -3408,55 +3427,29 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -3468,64 +3461,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "radium" -version = "0.7.0" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] [[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rand" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -3538,24 +3503,6 @@ dependencies = [ "rand_core 0.9.5", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - [[package]] name = "rand_core" version = "0.9.5" @@ -3566,22 +3513,10 @@ dependencies = [ ] [[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" +name = "rand_core" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "raw-window-handle" @@ -3595,45 +3530,44 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] name = "redox_users" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" dependencies = [ - "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3643,9 +3577,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -3654,26 +3588,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rend" -version = "0.4.2" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "bytes", "futures-core", "futures-util", @@ -3722,49 +3647,10 @@ dependencies = [ ] [[package]] -name = "rkyv" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rust_decimal" -version = "1.40.0" +name = "rustc-hash" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3787,11 +3673,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys", @@ -3800,9 +3686,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "log", "once_cell", @@ -3815,18 +3701,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "ring", "rustls-pki-types", @@ -3835,9 +3721,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -3877,9 +3763,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" dependencies = [ "dyn-clone", "ref-cast", @@ -3896,7 +3782,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -3906,22 +3792,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "security-framework" -version = "2.11.1" +name = "secret-service" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "5107b24b91445dd2aa449a258a1807b63240942157292354dc5bfdbeb8bc6db8" dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", + "aes", + "cbc", + "futures-util", + "getrandom 0.4.3", + "hkdf", + "hybrid-array", + "num", + "once_cell", + "serde", + "sha2 0.11.1", + "zbus", ] [[package]] @@ -3930,7 +3816,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3949,27 +3835,28 @@ dependencies = [ [[package]] name = "selectors" -version = "0.24.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.13.2", "cssparser", - "derive_more 0.99.20", - "fxhash", + "derive_more", "log", - "phf 0.8.0", - "phf_codegen 0.8.0", + "new_debug_unreachable", + "phf", + "phf_codegen", "precomputed-hash", + "rustc-hash", "servo_arc", "smallvec", ] [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -3977,9 +3864,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -4009,22 +3896,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -4035,16 +3922,17 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ - "indexmap 2.13.0", + "foldhash", + "indexmap 2.14.2", "itoa", "memchr", "serde", @@ -4054,13 +3942,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -4074,26 +3962,28 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" dependencies = [ "serde_core", ] [[package]] name = "serde_with" -version = "3.17.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "df9adc193c780ef8f159aee8b61e2d5801aaa555e6eb0947fe45530ec506296f" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.2", + "jiff", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.3", "serde_core", "serde_json", "serde_with_macros", @@ -4102,14 +3992,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.17.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "3e17bbc68e28663bbbb90df47e058aa7eda4fb445b89fe70457bb94fbccf6e49" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -4131,28 +4021,27 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "servo_arc" -version = "0.2.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" dependencies = [ - "nodrop", "stable_deref_trait", ] [[package]] name = "sha1" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -4162,15 +4051,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -4184,27 +4084,31 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] -name = "simdutf8" -version = "0.1.5" +name = "simd_cesu8" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] [[package]] -name = "siphasher" -version = "0.3.11" +name = "simdutf8" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" [[package]] name = "slab" @@ -4214,28 +4118,18 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" +version = "1.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4292,27 +4186,32 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_vcruntime" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7589a1859b09232522bb9edf076ca7fcf14ded96685d3fa629db73023ffbb7" + [[package]] name = "string_cache" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.11.3", + "phf_shared", "precomputed-hash", - "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -4342,9 +4241,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swift-rs" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +checksum = "cefd87076fd385308ee4aff597256c902f1fbb4d031de1558efc12f8ffefadd9" dependencies = [ "base64 0.21.7", "serde", @@ -4356,6 +4255,16 @@ 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", @@ -4364,9 +4273,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -4384,13 +4293,34 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -4420,23 +4350,23 @@ checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "tao" -version = "0.34.5" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" +checksum = "d5777b06fe6435126ae8d816eba269e050e1e10d302cf5461e9c49eccabc3548" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", - "dispatch", + "dbus", + "dispatch2", "dlopen2", "dpi", "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni", - "lazy_static", + "jni 0.21.1", "libc", "log", "ndk", @@ -4445,28 +4375,28 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", + "objc2-ui-kit", "parking_lot", + "percent-encoding", "raw-window-handle", - "scopeguard", "tao-macros", "unicode-segmentation", "url", "windows", - "windows-core 0.61.2", + "windows-core", "windows-version", "x11-dl", ] [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4483,9 +4413,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.10.2" +version = "2.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463ae8677aa6d0f063a900b9c41ecd4ac2b7ca82f0b058cc4491540e55b20129" +checksum = "5fb0244332cfb9cee7e2a568bf5da29a36ed8fdbd717f6f47a66b6b7b358c072" dependencies = [ "anyhow", "bytes", @@ -4498,7 +4428,7 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni", + "jni 0.21.1", "libc", "log", "mime", @@ -4522,7 +4452,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "tray-icon", "url", @@ -4534,9 +4464,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.5.5" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7bd893329425df750813e95bd2b643d5369d929438da96d5bbb7cc2c918f74" +checksum = "adddb0e648752aaac5da9c3c3c6a68e1e87cab55e3b757b18a9441ef8c3ac614" dependencies = [ "anyhow", "cargo_toml", @@ -4548,19 +4478,20 @@ dependencies = [ "semver", "serde", "serde_json", + "static_vcruntime", + "strsim", "tauri-utils", "tauri-winres", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.5.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac423e5859d9f9ccdd32e3cf6a5866a15bedbf25aa6630bcb2acde9468f6ae3" +checksum = "fb37631cf71dab5e8ab55e1bdd701e18a52653d90b78e71d0e5598b1e0a61316" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "brotli", "ico", "json-patch", @@ -4571,10 +4502,10 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", - "syn 2.0.117", + "sha2 0.10.9", + "syn 2.0.119", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "time", "url", "uuid", @@ -4583,23 +4514,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a1bd2861ff0c8766b1d38b32a6a410f6dc6532d4ef534c47cfb2236092f59" +checksum = "0cc38db58854c10fb5f91a887ed8bf82d3239bb92b5d8db86eda09e96d9963d1" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.5.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692a77abd8b8773e107a42ec0e05b767b8d2b7ece76ab36c6c3947e34df9f53f" +checksum = "67fb21a77e8f94e8beb3325e583102488659365af0a3948b7ea244c5b779c291" dependencies = [ "anyhow", "glob", @@ -4608,18 +4539,16 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-plugin-log" -version = "2.8.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7545bd67f070a4500432c826e2e0682146a1d6712aee22a2786490156b574d93" +checksum = "d83980f6765feb86cf2224959246be28b0488e14a23204a719f7f9deecfc64c9" dependencies = [ "android_logger", - "byte-unit", "fern", "log", "objc2", @@ -4630,15 +4559,15 @@ dependencies = [ "swift-rs", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", "time", ] [[package]] name = "tauri-plugin-opener" -version = "2.5.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc624469b06f59f5a29f874bbc61a2ed737c0f9c23ef09855a292c389c42e83f" +checksum = "53810be1b4fed22bb6ac3f4cab5a2b80d9391d1af436bda145607532bc0bb219" dependencies = [ "dunce", "glob", @@ -4650,7 +4579,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", "windows", "zbus", @@ -4658,15 +4587,15 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.10.0" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b885ffeac82b00f1f6fd292b6e5aabfa7435d537cef57d11e38a489956535651" +checksum = "7c55766d99cea69055904d1735b93c2049302b2e09effd462120deb5581d78e9" dependencies = [ "cookie", "dpi", "gtk", "http", - "jni", + "jni 0.21.1", "objc2", "objc2-ui-kit", "objc2-web-kit", @@ -4674,7 +4603,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", "webkit2gtk", "webview2-com", @@ -4683,18 +4612,16 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.10.0" +version = "2.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5204682391625e867d16584fedc83fc292fb998814c9f7918605c789cd876314" +checksum = "e1aa9d8b7a120f879f44fdc1053f7b7dbf416bf0bbc6a72b714dec46b782b52f" dependencies = [ "gtk", "http", - "jni", + "jni 0.21.1", "log", "objc2", "objc2-app-kit", - "objc2-foundation", - "once_cell", "percent-encoding", "raw-window-handle", "softbuffer", @@ -4710,24 +4637,24 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.8.2" +version = "2.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd169fccdff05eff2c1033210b9b94acd07a47e6fa9a3431cf09cfd4f01c87e" +checksum = "362ab21cd4cc713f2a02b1a9b5688198b1541cfb6907c4281e9190e0f0ef4aa3" dependencies = [ "anyhow", "brotli", "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", - "html5ever", "http", "infer", "json-patch", - "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf", + "plist", "proc-macro2", "quote", "regex", @@ -4738,8 +4665,8 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "thiserror 2.0.21", + "toml 1.1.8+spec-1.1.0", "url", "urlpattern", "uuid", @@ -4748,23 +4675,23 @@ dependencies = [ [[package]] name = "tauri-winres" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" +checksum = "c52bb6904475a6ca662f15ef787f18ade61d5740a1ee12c45d3b748efdb6f796" dependencies = [ "dunce", "embed-resource", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", ] [[package]] name = "tempfile" -version = "3.26.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4772,13 +4699,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ - "futf", - "mac", - "utf-8", + "new_debug_unreachable", ] [[package]] @@ -4792,11 +4717,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.21", ] [[package]] @@ -4807,28 +4732,27 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -4840,15 +4764,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -4865,9 +4789,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "zerovec", @@ -4875,51 +4799,42 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "tokio" -version = "1.49.0" +version = "1.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" dependencies = [ "rustls", "tokio", @@ -4927,14 +4842,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", + "futures-util", "pin-project-lite", "tokio", ] @@ -4953,17 +4869,17 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "1.1.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "serde_core", - "serde_spanned 1.0.4", - "toml_datetime 0.7.5+spec-1.1.0", + "serde_spanned 1.1.2", + "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.14", + "winnow 1.0.4", ] [[package]] @@ -4977,9 +4893,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] @@ -4990,7 +4906,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "toml_datetime 0.6.3", "winnow 0.5.40", ] @@ -5001,7 +4917,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.3", @@ -5010,30 +4926,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ - "indexmap 2.13.0", - "toml_datetime 0.7.5+spec-1.1.0", + "indexmap 2.14.2", + "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", - "winnow 0.7.14", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ - "winnow 0.7.14", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "tower" @@ -5052,20 +4968,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -5099,7 +5015,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5113,9 +5029,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.3" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72" dependencies = [ "crossbeam-channel", "dirs", @@ -5129,8 +5045,8 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.18", - "windows-sys 0.60.2", + "thiserror 2.0.21", + "windows-sys 0.61.2", ] [[package]] @@ -5156,7 +5072,7 @@ checksum = "0e48cea23f68d1f78eb7bc092881b6bb88d3d6b5b7e6234f6f9c911da1ffb221" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5167,60 +5083,19 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "uds_windows" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "winapi", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", + "windows-sys 0.61.2", ] [[package]] @@ -5231,30 +5106,30 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unicode-normalization" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +checksum = "993ad287eb20e8ba755312801cfe1413e0f25d604075863acaddca10b04c1833" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-xid" @@ -5283,58 +5158,43 @@ dependencies = [ [[package]] name = "urlpattern" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b" dependencies = [ + "icu_properties", "regex", "serde", - "unic-ucd-ident", "url", ] [[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8-width" -version = "0.1.8" +name = "utf8_iter" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" +checksum = "af3bd9d3e571c26fcce9d033b87ea5ab061b8d2ffe9b7a5675d810d68f03edf0" +dependencies = [ + "utf_types", +] [[package]] -name = "utf8_iter" -version = "1.0.4" +name = "utf_types" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "3a3b425286980a367278453f3b6d28cdcb134b574e5a35824a6ff5eebad50bb6" [[package]] name = "uuid" -version = "1.21.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514" dependencies = [ - "getrandom 0.4.1", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", ] -[[package]] -name = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - -[[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" @@ -5379,19 +5239,13 @@ dependencies = [ [[package]] name = "want" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b" dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -5400,30 +5254,20 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c" dependencies = [ "cfg-if", - "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", @@ -5431,23 +5275,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "5e14e0327cb5368ad60ccb22d04a9827a693c95a926d8d125e9fa39e0baec501" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", + "tokio", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5455,46 +5296,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.117", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a" dependencies = [ - "leb128fmt", - "wasmparser", + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", ] [[package]] -name = "wasm-metadata" -version = "0.244.0" +name = "wasm-bindgen-shared" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e" dependencies = [ - "anyhow", - "indexmap 2.13.0", - "wasm-encoder", - "wasmparser", + "unicode-ident", ] [[package]] @@ -5511,27 +5330,37 @@ dependencies = [ ] [[package]] -name = "wasmparser" -version = "0.244.0" +name = "web-sys" +version = "0.3.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "d7d179596ff5ec0f6de4db64d54011bde6289cc49603d3a6e4ce3f329207ab88" dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "semver", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "web-sys" -version = "0.3.91" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 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" @@ -5578,25 +5407,23 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "f5f280bbb2b287bc8e7de7e3852945a0ff50d1bbcb5ed42b6c7a568c546df171" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6" dependencies = [ "webview2-com-macros", "webview2-com-sys", "windows", - "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows-core", ] [[package]] @@ -5607,18 +5434,18 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "webview2-com-sys" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.21", "windows", - "windows-core 0.61.2", + "windows-core", ] [[package]] @@ -5660,52 +5487,39 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580" dependencies = [ "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", + "objc2-quartz-core", "raw-window-handle", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "windows-version", ] [[package]] name = "windows" -version = "0.61.3" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.61.2", + "windows-core", "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" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-core", ] [[package]] @@ -5716,19 +5530,19 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] name = "windows-future" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", + "windows-core", + "windows-link", "windows-threading", ] @@ -5740,7 +5554,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5751,15 +5565,9 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "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" @@ -5767,40 +5575,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-numerics" -version = "0.2.0" +name = "windows-native-keyring-store" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +checksum = "063426e76fdec7438d56bb777f67e318a84a25c707b07e575cb8b78e10c028f8" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", + "byteorder", + "keyring-core", + "regex", + "windows-sys 0.61.2", + "zeroize", ] [[package]] -name = "windows-result" -version = "0.3.4" +name = "windows-numerics" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-link 0.1.3", + "windows-core", + "windows-link", ] [[package]] -name = "windows-result" -version = "0.4.1" +name = "windows-registry" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.2.1", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-strings" -version = "0.4.2" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -5809,7 +5623,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -5821,15 +5635,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -5839,31 +5644,13 @@ 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", + "windows-link", ] [[package]] @@ -5881,21 +5668,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -5905,37 +5677,20 @@ 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_gnullvm", "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" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -5944,7 +5699,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -5953,180 +5708,90 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.5.40" @@ -6138,147 +5803,54 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10" dependencies = [ "cfg-if", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.13.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "wry" -version = "0.54.2" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a" +checksum = "759c50ddad0ef9913bb5496cb9d509a50433a3b78cb0238d61105526589cf0e9" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "block2", "cookie", "crossbeam-channel", "dirs", + "dom_query", "dpi", "dunce", "gdkx11", "gtk", - "html5ever", "http", "javascriptcore-rs", - "jni", - "kuchikiki", + "jni 0.21.1", "libc", "ndk", "objc2", @@ -6287,19 +5859,18 @@ dependencies = [ "objc2-foundation", "objc2-ui-kit", "objc2-web-kit", - "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", "windows", - "windows-core 0.61.2", + "windows-core", "windows-version", "x11-dl", ] @@ -6336,9 +5907,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -6347,21 +5918,21 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "synstructure", ] [[package]] name = "zbus" -version = "5.14.0" +version = "5.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" +checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907" dependencies = [ "async-broadcast", "async-executor", @@ -6386,22 +5957,33 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow 0.7.14", + "winnow 1.0.4", "zbus_macros", "zbus_names", "zvariant", ] +[[package]] +name = "zbus-secret-service-keyring-store" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74801d001b9e7729adb4f1825b67b398185fed424749aa3d8bacf70417137d9a" +dependencies = [ + "keyring-core", + "secret-service", + "zbus", +] + [[package]] name = "zbus_macros" -version = "5.14.0" +version = "5.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" +checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "zbus_names", "zvariant", "zvariant_utils", @@ -6409,81 +5991,76 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.1" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +checksum = "812a12be4ead7a59e18ea8f047d08add0066b73bc62fc1467066a2472ae088dd" dependencies = [ "serde", - "winnow 0.7.14", + "winnow 1.0.4", "zvariant", ] +[[package]] +name = "zcheapstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939f186d9ecebe044315a5cb6d6f78568bbc21152adc954d5a0c2f58bdbc9920" +dependencies = [ + "serde", +] + [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -6492,9 +6069,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "yoke", "zerofrom", @@ -6503,57 +6080,64 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] +[[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.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zvariant" -version = "5.10.0" +version = "5.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" +checksum = "80bf6d6cd6a4b601acb64cfb8284cdc643fcfa75ef26ae3c46ec8aa4e8a1fbb7" dependencies = [ "endi", "enumflags2", "serde", - "winnow 0.7.14", + "winnow 1.0.4", + "zcheapstr", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.10.0" +version = "5.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" +checksum = "ef2672456ba1cb54b5eaec136e63135b3c7495fb938e53b28a62e633496d486d" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "3.3.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3" dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.117", - "winnow 0.7.14", + "syn 3.0.9", + "winnow 1.0.4", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index be75ba4..44b07fa 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,13 +22,13 @@ tauri = { version = "2", features = [] } tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" -mongodb = "3.5.0" -futures = "0.3.31" -uuid = "1.20.0" -tokio = { version = "1.49.0", features = ["fs"] } -async-trait = "0.1" -thiserror = "2.0.18" -log = "0.4.29" +mongodb = "3.9.1" +futures = "0.3.34" +uuid = "1.29.0" +tokio = { version = "1.54.1", features = ["fs"] } +async-trait = "0.1.92" +thiserror = "2.0.21" +log = "0.4.35" tauri-plugin-log = "2" url = "2.5.8" -keyring = { version = "3.6.3", features = ["apple-native", "windows-native", "linux-native-sync-persistent", "vendored" ] } +keyring = "4.2.0" From 094ed267da4b81800cb0b2956d31a77bf79042e4 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:46:13 +0100 Subject: [PATCH 08/33] fix: shell functions in queries that silently matched nothing the parser turns shell functions into extended json, and bson in the rust core reads those shapes as bson types. what bson can't read stays a plain object, and the query matched nothing without an error: ISODate("2024-01-01") (bson wants a full rfc 3339 date), an ObjectId that isn't 24 hex characters, BinData with its subtype as a number. now dates are normalised to utc rfc 3339 (a date or date-time without zone is utc, as in the shell), and every function checks its arguments and throws a parse error the query tab shows. RegExp and /re/flags literals become $regularExpression, which also works inside $in. added: NumberInt, UUID, new before a function, dotted keys without quotes, numbers with exponents. a missing comma, an unterminated string or regex, and anything after the query are errors now instead of being skipped. checked: 70 tests; a scratch program with bson 2.15 turns every shape the parser produces into the expected bson type. --- src/utils/queryParser/generateTokens.ts | 61 +++++-- src/utils/queryParser/helpers.ts | 4 - src/utils/queryParser/index.ts | 2 +- src/utils/queryParser/parser.ts | 30 +++- src/utils/queryParser/test/parser.test.ts | 4 +- .../queryParser/test/query-parser.test.ts | 167 ++++++++++++++++-- src/utils/queryParser/test/tokens.test.ts | 38 ++++ src/utils/queryParser/transformFunction.ts | 123 +++++++++++-- src/utils/queryParser/types.ts | 9 +- 9 files changed, 382 insertions(+), 56 deletions(-) diff --git a/src/utils/queryParser/generateTokens.ts b/src/utils/queryParser/generateTokens.ts index 3a9099d..ff891f9 100644 --- a/src/utils/queryParser/generateTokens.ts +++ b/src/utils/queryParser/generateTokens.ts @@ -1,6 +1,11 @@ -import { isNumber, isWhitespace } from "./helpers"; +import { isWhitespace } from "./helpers"; import { T, Token } from "./types"; +const NUMBER = /^-?\d+(\.\d+)?([eE][+-]?\d+)?/; +// dots are allowed after the first character, so `user.name` can be a key without quotes +const IDENT_START = /[a-zA-Z_$]/; +const IDENT_PART = /[a-zA-Z0-9_$.]/; + export function generateTokens(input: string) { const tokens: Token[] = []; let i = 0; @@ -52,45 +57,79 @@ export function generateTokens(input: string) { const quote = ch; let str = ""; let escaped = false; + let closed = false; while (i < input.length) { i++; const current = input[i]; + if (current === undefined) break; + if (escaped) { str += current; escaped = false; } else if (current === "\\") { escaped = true; } else if (current === quote) { + closed = true; break; } else { str += current; } } + + if (!closed) throw new Error(`Unterminated string starting with ${quote}${str}`); + i++; tokens.push({ type: T.STRING, value: str }); continue; } - if (isNumber(ch) || (ch === "-" && isNumber(input[i + 1]))) { - let num = ""; - if (ch === "-") { - num += "-"; + // there is no division in queries, so a slash always starts a regex literal + if (ch === "/") { + let pattern = ""; + let closed = false; + i++; + + while (i < input.length) { + const current = input[i]; + if (current === "\\" && i + 1 < input.length) { + // keep the escape, it belongs to the regex + pattern += current + input[i + 1]; + i += 2; + continue; + } + if (current === "/") { + closed = true; + i++; + break; + } + pattern += current; i++; } - while (i < input.length && /[0-9.]/.test(input[i])) { - num += input[i++]; + if (!closed) throw new Error(`Unterminated regular expression /${pattern}`); + + let flags = ""; + while (i < input.length && /[a-z]/.test(input[i])) { + flags += input[i++]; } - tokens.push({ type: T.NUMBER, value: Number(num) }); + + tokens.push({ type: T.REGEX, value: pattern, flags }); + continue; + } + + const number = NUMBER.exec(input.slice(i)); + if (number) { + tokens.push({ type: T.NUMBER, value: Number(number[0]) }); + i += number[0].length; continue; } - // Identifiers: field names, $operators, function names, true/false/null - if (/[a-zA-Z_$]/.test(ch)) { + // Identifiers: field names, $operators, function names, true/false/null, new + if (IDENT_START.test(ch)) { let ident = ""; - while (i < input.length && /[a-zA-Z0-9_$]/.test(input[i])) { + while (i < input.length && IDENT_PART.test(input[i])) { ident += input[i++]; } tokens.push({ type: T.IDENT, value: ident }); diff --git a/src/utils/queryParser/helpers.ts b/src/utils/queryParser/helpers.ts index 05574c0..52788c9 100644 --- a/src/utils/queryParser/helpers.ts +++ b/src/utils/queryParser/helpers.ts @@ -1,7 +1,3 @@ -export function isNumber(ch: string) { - return /\d/.test(ch); -} - export function isWhitespace(ch: string) { return /\s/.test(ch) } \ No newline at end of file diff --git a/src/utils/queryParser/index.ts b/src/utils/queryParser/index.ts index 3eef32b..f589387 100644 --- a/src/utils/queryParser/index.ts +++ b/src/utils/queryParser/index.ts @@ -4,5 +4,5 @@ import { createParser } from "./parser"; export function parseMongoDbQuery(query: string) { const tokens = generateTokens(query); const parser = createParser(tokens); - return parser.parseValue(); + return parser.parseQuery(); } \ No newline at end of file diff --git a/src/utils/queryParser/parser.ts b/src/utils/queryParser/parser.ts index 29f5798..90e5d7e 100644 --- a/src/utils/queryParser/parser.ts +++ b/src/utils/queryParser/parser.ts @@ -1,10 +1,10 @@ -import { transformFunction } from "./transformFunction" +import { regexToExtendedJson, transformFunction } from "./transformFunction" import { T, Token } from "./types" export function createParser(tokens: Token[]) { let pos = 0 - + const peek = () => tokens[pos] const consume = (type?: string) => { @@ -25,6 +25,7 @@ export function createParser(tokens: Token[]) { if (token.type === T.LBRACKET) return parseArray() if (token.type === T.STRING) { consume(); return token.value } if (token.type === T.NUMBER) { consume(); return token.value } + if (token.type === T.REGEX) { consume(); return regexToExtendedJson(String(token.value), token.flags ?? '') } if (token.type === T.IDENT) { if (token.value === 'true') { consume(); return true } @@ -37,12 +38,21 @@ export function createParser(tokens: Token[]) { throw new Error(`Unexpected token: ${token.type}`) } + // a query is one value and nothing after it + function parseQuery() { + const value = parseValue() + if (!check(T.EOF)) { + throw new Error(`Unexpected ${peek().type} after the end of the query`) + } + return value + } + function parseObject() { consume(T.LBRACE) const obj: any = {} while (!check(T.RBRACE)) { - + const keyToken = consume() if (keyToken.type !== T.IDENT && keyToken.type !== T.STRING) { throw new Error(`Expected object key, got ${keyToken.type}`) @@ -56,6 +66,7 @@ export function createParser(tokens: Token[]) { obj[key] = value if (check(T.COMMA)) consume() + else if (!check(T.RBRACE)) throw new Error(`Expected , or } but got ${peek().type}`) } consume(T.RBRACE) @@ -69,6 +80,7 @@ export function createParser(tokens: Token[]) { while (!check(T.RBRACKET)) { arr.push(parseValue()) if (check(T.COMMA)) consume() + else if (!check(T.RBRACKET)) throw new Error(`Expected , or ] but got ${peek().type}`) } consume(T.RBRACKET) @@ -76,7 +88,12 @@ export function createParser(tokens: Token[]) { } function parseFunctionCall(): any { - const name = consume(T.IDENT).value + let name = consume(T.IDENT).value + + // `new Date(...)` is the same as `Date(...)` in a query + if (name === 'new' && check(T.IDENT)) { + name = consume(T.IDENT).value + } if(!name) throw new Error(`Expected value, got undefined`) @@ -90,11 +107,12 @@ export function createParser(tokens: Token[]) { while (!check(T.RPAREN)) { args.push(parseValue()) if (check(T.COMMA)) consume() + else if (!check(T.RPAREN)) throw new Error(`Expected , or ) but got ${peek().type}`) } consume(T.RPAREN) return transformFunction(String(name), args) } - return { parseValue } -} \ No newline at end of file + return { parseValue, parseQuery } +} diff --git a/src/utils/queryParser/test/parser.test.ts b/src/utils/queryParser/test/parser.test.ts index cd775cd..ddaaf3a 100644 --- a/src/utils/queryParser/test/parser.test.ts +++ b/src/utils/queryParser/test/parser.test.ts @@ -25,7 +25,7 @@ test("Test function calll parser", () => { { type: "COLON" }, { type: "IDENT", value: "ObjectId" }, { type: "LPAREN" }, - { type: "STRING", value: "..." }, + { type: "STRING", value: "507f1f77bcf86cd799439011" }, { type: "RPAREN" }, { type: "RBRACE" }, { type: "EOF" }, @@ -33,7 +33,7 @@ test("Test function calll parser", () => { expect(parser.parseValue()).toMatchObject({ _id: { - $oid: "...", + $oid: "507f1f77bcf86cd799439011", }, }); }); diff --git a/src/utils/queryParser/test/query-parser.test.ts b/src/utils/queryParser/test/query-parser.test.ts index c46badb..190eacd 100644 --- a/src/utils/queryParser/test/query-parser.test.ts +++ b/src/utils/queryParser/test/query-parser.test.ts @@ -1,10 +1,12 @@ import { describe, expect, it } from "vitest" import { parseMongoDbQuery } from ".." +const ID = '507f1f77bcf86cd799439011' + describe('parseMongoQuery — real-world queries', () => { - it('query from the original question', () => { - expect(parseMongoDbQuery('{ user: ObjectId("abc123"), age: { $gt: 15 } }')).toEqual({ - user: { $oid: 'abc123' }, + it('ObjectId and an operator', () => { + expect(parseMongoDbQuery(`{ user: ObjectId("${ID}"), age: { $gt: 15 } }`)).toEqual({ + user: { $oid: ID }, age: { $gt: 15 }, }) }) @@ -25,28 +27,32 @@ describe('parseMongoQuery — real-world queries', () => { }) }) - it('date range query', () => { + it('date range query with date-only ISODates', () => { expect( parseMongoDbQuery( '{ createdAt: { $gte: ISODate("2024-01-01"), $lt: ISODate("2025-01-01") } }' ) ).toEqual({ createdAt: { - $gte: { $date: '2024-01-01' }, - $lt: { $date: '2025-01-01' }, + $gte: { $date: '2024-01-01T00:00:00.000Z' }, + $lt: { $date: '2025-01-01T00:00:00.000Z' }, }, }) }) - it('nested document with ObjectId reference', () => { + it('quoted dotted keys', () => { expect( - parseMongoDbQuery('{ "user._id": ObjectId("abc"), "user.role": "admin" }') + parseMongoDbQuery(`{ "user._id": ObjectId("${ID}"), "user.role": "admin" }`) ).toEqual({ - 'user._id': { $oid: 'abc' }, + 'user._id': { $oid: ID }, 'user.role': 'admin', }) }) + it('dotted keys without quotes', () => { + expect(parseMongoDbQuery('{ user.address.city: "Graz" }')).toEqual({ 'user.address.city': 'Graz' }) + }) + it('$elemMatch query', () => { expect( parseMongoDbQuery('{ scores: { $elemMatch: { $gt: 80, $lt: 100 } } }') @@ -58,16 +64,98 @@ describe('parseMongoQuery — real-world queries', () => { it('complex query with multiple types', () => { expect( parseMongoDbQuery(`{ - _id: ObjectId("507f1f77bcf86cd799439011"), + _id: ObjectId("${ID}"), age: { $gte: 18, $lte: 65 }, status: { $in: ["active", "trial"] }, - deleted: false + deleted: false, + note: null }`) ).toEqual({ - _id: { $oid: '507f1f77bcf86cd799439011' }, + _id: { $oid: ID }, age: { $gte: 18, $lte: 65 }, status: { $in: ['active', 'trial'] }, deleted: false, + note: null, + }) + }) + + it('accepts a trailing comma', () => { + expect(parseMongoDbQuery('{ a: 1, }')).toEqual({ a: 1 }) + expect(parseMongoDbQuery('{ a: [1, 2,] }')).toEqual({ a: [1, 2] }) + }) + + it('an empty object', () => { + expect(parseMongoDbQuery('{ }')).toEqual({}) + }) + + it('numbers with exponents and decimals', () => { + expect(parseMongoDbQuery('{ a: 1e5, b: -2.5E-3, c: 0.5 }')).toEqual({ a: 100000, b: -0.0025, c: 0.5 }) + }) +}) + +describe('parseMongoQuery — shell functions', () => { + it('lowercases ObjectId hex', () => { + expect(parseMongoDbQuery(`{ _id: ObjectId("${ID.toUpperCase()}") }`)).toEqual({ _id: { $oid: ID } }) + }) + + it('new before a function is ignored', () => { + expect(parseMongoDbQuery('{ at: new Date("2024-03-01") }')).toEqual({ at: { $date: '2024-03-01T00:00:00.000Z' } }) + expect(parseMongoDbQuery(`{ _id: new ObjectId("${ID}") }`)).toEqual({ _id: { $oid: ID } }) + }) + + it('reads a date-time without zone as UTC', () => { + expect(parseMongoDbQuery('{ at: ISODate("2024-03-01T10:15") }')).toEqual({ at: { $date: '2024-03-01T10:15:00.000Z' } }) + expect(parseMongoDbQuery('{ at: ISODate("2024-03-01T10:15:30.5") }')).toEqual({ at: { $date: '2024-03-01T10:15:30.500Z' } }) + }) + + it('converts a date with an offset to UTC', () => { + expect(parseMongoDbQuery('{ at: ISODate("2024-03-01T10:00:00+02:00") }')).toEqual({ at: { $date: '2024-03-01T08:00:00.000Z' } }) + }) + + it('takes milliseconds since the epoch', () => { + expect(parseMongoDbQuery('{ at: Date(0) }')).toEqual({ at: { $date: '1970-01-01T00:00:00.000Z' } }) + }) + + it('Date() without argument is now', () => { + const before = Date.now() + const { at } = parseMongoDbQuery('{ at: new Date() }') as { at: { $date: string } } + const ms = Date.parse(at.$date) + expect(ms).toBeGreaterThanOrEqual(before - 1000) + expect(ms).toBeLessThanOrEqual(Date.now() + 1000) + }) + + it('NumberLong, NumberInt and NumberDecimal keep their digits as strings', () => { + expect(parseMongoDbQuery('{ a: NumberLong("9007199254740993"), b: NumberLong(5), c: NumberInt(-7), d: NumberDecimal("1.10") }')).toEqual({ + a: { $numberLong: '9007199254740993' }, + b: { $numberLong: '5' }, + c: { $numberInt: '-7' }, + d: { $numberDecimal: '1.10' }, + }) + }) + + it('Timestamp', () => { + expect(parseMongoDbQuery('{ ts: Timestamp(1700000000, 3) }')).toEqual({ ts: { $timestamp: { t: 1700000000, i: 3 } } }) + }) + + it('BinData with the subtype as hex', () => { + expect(parseMongoDbQuery('{ b: BinData(4, "AAEC") }')).toEqual({ b: { $binary: { base64: 'AAEC', subType: '04' } } }) + expect(parseMongoDbQuery('{ b: BinData(128, "") }')).toEqual({ b: { $binary: { base64: '', subType: '80' } } }) + }) + + it('UUID as binary subtype 4', () => { + expect(parseMongoDbQuery('{ u: UUID("00112233-4455-6677-8899-aabbccddeeff") }')).toEqual({ + u: { $binary: { base64: 'ABEiM0RVZneImaq7zN3u/w==', subType: '04' } }, + }) + }) + + it('RegExp and regex literals become $regularExpression with sorted options', () => { + expect(parseMongoDbQuery('{ name: RegExp("^al", "mi") }')).toEqual({ name: { $regularExpression: { pattern: '^al', options: 'im' } } }) + expect(parseMongoDbQuery('{ name: /^al/i }')).toEqual({ name: { $regularExpression: { pattern: '^al', options: 'i' } } }) + expect(parseMongoDbQuery('{ name: { $in: [/a\\/b/, /c/] } }')).toEqual({ + name: { $in: [ + { $regularExpression: { pattern: 'a\\/b', options: '' } }, + { $regularExpression: { pattern: 'c', options: '' } }, + ] }, }) }) }) @@ -82,14 +170,61 @@ describe('parseMongoQuery — error handling', () => { }) it('throws on bare unknown identifier', () => { - expect(() => parseMongoDbQuery('{ x: unknownIdent }')).toThrow() + expect(() => parseMongoDbQuery('{ x: unknownIdent }')).toThrow(/Unknown identifier/) }) it('throws on missing colon', () => { expect(() => parseMongoDbQuery('{ a 1 }')).toThrow() }) - it('accepts a trailing comma', () => { - expect(parseMongoDbQuery('{ a: 1, }')).toEqual({ a: 1 }) + it('throws on a missing comma', () => { + expect(() => parseMongoDbQuery('{ a: 1 b: 2 }')).toThrow(/Expected , or }/) + expect(() => parseMongoDbQuery('{ a: [1 2] }')).toThrow(/Expected , or ]/) + }) + + it('throws on anything after the query', () => { + expect(() => parseMongoDbQuery('{ a: 1 } }')).toThrow(/after the end of the query/) + expect(() => parseMongoDbQuery('{ a: 1 } { b: 2 }')).toThrow(/after the end of the query/) + }) + + it('throws on an unknown function', () => { + expect(() => parseMongoDbQuery('{ a: Foo(1) }')).toThrow(/Unknown function: Foo/) + }) + + it('throws on an ObjectId that is not 24 hex characters', () => { + expect(() => parseMongoDbQuery('{ _id: ObjectId("abc123") }')).toThrow(/ObjectId/) + expect(() => parseMongoDbQuery('{ _id: ObjectId("507f1f77bcf86cd79943901z") }')).toThrow(/ObjectId/) + expect(() => parseMongoDbQuery('{ _id: ObjectId() }')).toThrow(/ObjectId/) + }) + + it('throws on an invalid date', () => { + expect(() => parseMongoDbQuery('{ at: ISODate("yesterday") }')).toThrow(/Invalid date/) + expect(() => parseMongoDbQuery('{ at: ISODate("2024-13-45") }')).toThrow(/Invalid date/) + expect(() => parseMongoDbQuery('{ at: Date(2024, 1, 1) }')).toThrow(/one argument/) + }) + + it('throws on numbers that are not integers where integers are needed', () => { + expect(() => parseMongoDbQuery('{ a: NumberLong("12x") }')).toThrow(/NumberLong/) + expect(() => parseMongoDbQuery('{ a: NumberInt(1.5) }')).toThrow(/NumberInt/) + expect(() => parseMongoDbQuery('{ a: NumberInt(2147483648) }')).toThrow(/out of range/) + expect(() => parseMongoDbQuery('{ a: NumberDecimal("abc") }')).toThrow(/NumberDecimal/) + expect(() => parseMongoDbQuery('{ a: Timestamp(1) }')).toThrow(/Timestamp/) + expect(() => parseMongoDbQuery('{ a: Timestamp(-1, 0) }')).toThrow(/Timestamp/) }) -}) \ No newline at end of file + + it('throws on invalid binary data', () => { + expect(() => parseMongoDbQuery('{ b: BinData(256, "AA==") }')).toThrow(/subtype/) + expect(() => parseMongoDbQuery('{ b: BinData(0, "not base64!") }')).toThrow(/base64/) + expect(() => parseMongoDbQuery('{ u: UUID("1234") }')).toThrow(/UUID/) + }) + + it('throws on unsupported regex flags', () => { + expect(() => parseMongoDbQuery('{ a: /x/g }')).toThrow(/flags/) + expect(() => parseMongoDbQuery('{ a: RegExp("x", "y") }')).toThrow(/flags/) + }) + + it('throws on an unterminated string or regex', () => { + expect(() => parseMongoDbQuery('{ a: "open }')).toThrow(/Unterminated string/) + expect(() => parseMongoDbQuery('{ a: /open }')).toThrow(/Unterminated regular expression/) + }) +}) diff --git a/src/utils/queryParser/test/tokens.test.ts b/src/utils/queryParser/test/tokens.test.ts index 07452e3..e2c10ed 100644 --- a/src/utils/queryParser/test/tokens.test.ts +++ b/src/utils/queryParser/test/tokens.test.ts @@ -98,3 +98,41 @@ it("throws on unexpected character", () => { expect(() => generateTokens("{")).not.toThrow(); // just brace is fine expect(() => generateTokens("@")).toThrow(/Unexpected character/); }); + +it("tokenizes numbers with exponents", () => { + expect(generateTokens("1e5 -2.5E-3 7E+2").map((t) => t.value)).toEqual([100000, -0.0025, 700, undefined]); +}); + +it("tokenizes dotted identifiers as one identifier", () => { + const [tok] = generateTokens("user.address.city"); + expect(tok).toEqual({ type: "IDENT", value: "user.address.city" }); +}); + +it("tokenizes a regex literal with its flags", () => { + const [tok] = generateTokens("/^a\\/b$/im"); + expect(tok).toEqual({ type: "REGEX", value: "^a\\/b$", flags: "im" }); +}); + +it("tokenizes a regex literal without flags", () => { + const [tok, next] = generateTokens("/x/,"); + expect(tok).toEqual({ type: "REGEX", value: "x", flags: "" }); + expect(next).toEqual({ type: "COMMA" }); +}); + +it("keeps escaped characters of a string", () => { + const [tok] = generateTokens("'it\\'s'"); + expect(tok).toEqual({ type: "STRING", value: "it's" }); +}); + +it("throws on an unterminated string", () => { + expect(() => generateTokens('"abc')).toThrow(/Unterminated string/); + expect(() => generateTokens('"abc\\')).toThrow(/Unterminated string/); +}); + +it("throws on an unterminated regex", () => { + expect(() => generateTokens("/abc")).toThrow(/Unterminated regular expression/); +}); + +it("throws on a lone minus", () => { + expect(() => generateTokens("-")).toThrow(/Unexpected character/); +}); diff --git a/src/utils/queryParser/transformFunction.ts b/src/utils/queryParser/transformFunction.ts index 978e851..9f41cca 100644 --- a/src/utils/queryParser/transformFunction.ts +++ b/src/utils/queryParser/transformFunction.ts @@ -1,21 +1,118 @@ +// Shell functions become extended JSON; bson in the Rust core reads these shapes as BSON types. +// Anything bson can't read would silently stay a plain object, so invalid input throws here. + +const OBJECT_ID = /^[0-9a-fA-F]{24}$/; +const UUID = /^[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$/; +const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/; +const HAS_ZONE = /(Z|[+-]\d{2}:?\d{2})$/i; +const INTEGER = /^-?\d+$/; +const DECIMAL = /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/; +const BASE64 = /^[A-Za-z0-9+/]*={0,2}$/; +const REGEX_FLAGS = /^[imsxu]*$/; + +const INT32_MIN = -2147483648; +const INT32_MAX = 2147483647; + +export function toIsoDate(arg: unknown): string { + // Date() and new Date() without an argument mean now + if (arg === undefined) return new Date().toISOString(); + + if (typeof arg === 'number') { + const date = new Date(arg); + if (Number.isNaN(date.getTime())) throw new Error(`Invalid date: ${arg}`); + return date.toISOString(); + } + + if (typeof arg !== 'string') throw new Error(`Invalid date: ${JSON.stringify(arg)}`); + + let text = arg.trim(); + // the shell reads a date without a zone as UTC, JavaScript would read a date-time as local time + if (DATE_ONLY.test(text)) text += 'T00:00:00Z'; + else if (text.includes('T') && !HAS_ZONE.test(text)) text += 'Z'; + + const ms = Date.parse(text); + if (Number.isNaN(ms)) throw new Error(`Invalid date: "${arg}"`); + return new Date(ms).toISOString(); +} + +export function regexToExtendedJson(pattern: string, flags: string) { + if (!REGEX_FLAGS.test(flags)) { + throw new Error(`Unsupported regular expression flags: ${flags} (MongoDB knows i, m, s, x, u)`); + } + // bson stores the options sorted + const options = [...new Set(flags)].sort().join(''); + return { $regularExpression: { pattern, options } }; +} + +function integerText(name: string, arg: unknown): string { + const text = String(arg); + if (!INTEGER.test(text)) throw new Error(`${name} needs an integer, got ${JSON.stringify(arg)}`); + return text; +} + +function uuidToBase64(text: string): string { + const hex = text.replace(/-/g, ''); + let binary = ''; + for (let i = 0; i < hex.length; i += 2) { + binary += String.fromCharCode(parseInt(hex.slice(i, i + 2), 16)); + } + return btoa(binary); +} + export function transformFunction(name: string, args: any[]) { switch (name) { - case 'ObjectId': - return { $oid: args[0] } + case 'ObjectId': { + const id = args[0]; + if (typeof id !== 'string' || !OBJECT_ID.test(id)) { + throw new Error(`ObjectId needs 24 hexadecimal characters, got ${JSON.stringify(id)}`); + } + return { $oid: id.toLowerCase() }; + } case 'ISODate': case 'Date': - return { $date: args[0] } + if (args.length > 1) throw new Error(`${name} takes one argument, e.g. ${name}("2024-01-01")`); + return { $date: toIsoDate(args[0]) }; case 'NumberLong': - return { $numberLong: String(args[0]) } - case 'NumberDecimal': - return { $numberDecimal: String(args[0]) } - case 'Timestamp': - return { $timestamp: { t: args[0], i: args[1] } } - case 'BinData': - return { $binary: { base64: args[1], subType: args[0] } } + return { $numberLong: integerText(name, args[0]) }; + case 'NumberInt': { + const text = integerText(name, args[0]); + const value = Number(text); + if (value < INT32_MIN || value > INT32_MAX) throw new Error(`NumberInt is out of range: ${text}`); + return { $numberInt: text }; + } + case 'NumberDecimal': { + const text = String(args[0]); + if (!DECIMAL.test(text)) throw new Error(`NumberDecimal needs a number, got ${JSON.stringify(args[0])}`); + return { $numberDecimal: text }; + } + case 'Timestamp': { + const [t, i] = args; + if (!Number.isInteger(t) || !Number.isInteger(i) || t < 0 || i < 0) { + throw new Error('Timestamp needs two non-negative integers, e.g. Timestamp(1700000000, 1)'); + } + return { $timestamp: { t, i } }; + } + case 'BinData': { + const [subtype, base64] = args; + if (!Number.isInteger(subtype) || subtype < 0 || subtype > 255) { + throw new Error(`BinData needs a subtype from 0 to 255, got ${JSON.stringify(subtype)}`); + } + if (typeof base64 !== 'string' || !BASE64.test(base64)) { + throw new Error('BinData needs base64 data as second argument'); + } + return { $binary: { base64, subType: subtype.toString(16).padStart(2, '0') } }; + } + case 'UUID': { + const id = args[0]; + if (typeof id !== 'string' || !UUID.test(id)) { + throw new Error(`UUID needs 32 hexadecimal characters, got ${JSON.stringify(id)}`); + } + return { $binary: { base64: uuidToBase64(id), subType: '04' } }; + } case 'RegExp': - return { $regex: args[0], $options: args[1] ?? '' } + if (typeof args[0] !== 'string') throw new Error('RegExp needs a pattern string'); + return regexToExtendedJson(args[0], typeof args[1] === 'string' ? args[1] : ''); default: - throw new Error(`Unknown function: ${name}`) + throw new Error(`Unknown function: ${name}`); } -} \ No newline at end of file +} diff --git a/src/utils/queryParser/types.ts b/src/utils/queryParser/types.ts index 0aa79a5..3cc7c38 100644 --- a/src/utils/queryParser/types.ts +++ b/src/utils/queryParser/types.ts @@ -9,12 +9,15 @@ export const T = { COLON: 'COLON', // : COMMA: 'COMMA', // , STRING: 'STRING', // "hello" or 'hello' - NUMBER: 'NUMBER', // 42, 3.14, -1 - IDENT: 'IDENT', // user, $gt, ObjectId, true, null + NUMBER: 'NUMBER', // 42, 3.14, -1, 1e5 + IDENT: 'IDENT', // user, user.name, $gt, ObjectId, true, null + REGEX: 'REGEX', // /pattern/flags EOF: 'EOF', } export type Token = { type: string; value?: string | number; -} \ No newline at end of file + // only on REGEX tokens + flags?: string; +} From 95a3e7b5da7249603d32d8e8aff15f7216383818 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:47:21 +0100 Subject: [PATCH 09/33] fix: unsubscribing a shortcut called the subscriber CommandRegistry.unsubscribe used findIndex(subscriber), which calls the subscriber as a predicate. for the query view that ran a query, and because the returned promise is truthy it removed the first subscriber, whichever it was. it uses indexOf now. shortcuts are bound to "mod", which is cmd on macos and ctrl elsewhere, so mod+w, mod+shift+d and mod+enter. tauri's default macos menu binds cmd+w to "close window"; on macos the app now builds that menu without it (src-tauri/src/menu.rs), keeping the edit menu that copy and paste need there. the menu is compiled on every platform but only used on macos, and can't be checked without a mac. tests run with tauri's ipc mocked (src/test/setup.ts), so code that logs can be tested. new tests for the key strings, the registry and the bindings. --- CLAUDE.md | 2 +- src-tauri/src/lib.rs | 9 ++- src-tauri/src/menu.rs | 66 +++++++++++++++ .../shortcuts/config/default-binding.ts | 6 +- .../shortcuts/registry/CommandRegistry.ts | 2 +- .../shortcuts/test/CommandRegistry.test.ts | 81 +++++++++++++++++++ .../shortcuts/test/eventToKeyString.test.ts | 39 +++++++++ .../shortcuts/utils/eventToKeyString.ts | 12 ++- src/test/setup.ts | 11 +++ vite.config.ts | 1 + 10 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 src-tauri/src/menu.rs create mode 100644 src/domains/shortcuts/test/CommandRegistry.test.ts create mode 100644 src/domains/shortcuts/test/eventToKeyString.test.ts create mode 100644 src/test/setup.ts diff --git a/CLAUDE.md b/CLAUDE.md index 2523909..1b48a3d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -70,7 +70,7 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt ## Testing - Every piece of logic gets unit tests, for the regular cases and every edge case you can think of: empty and missing input, boundaries, wrong kinds of values, failing collaborators (MongoDB, keyring, file system). -- Frontend: vitest in happy-dom (the `test` block of `vite.config.ts`), files `*.test.ts` in a `test/` folder next to the code (as `src/utils/queryParser/test/`, `src/composables/table/test/`). Pull logic out of components into composables or `utils` so it can be tested without mounting. +- Frontend: vitest in happy-dom (the `test` block of `vite.config.ts`), files `*.test.ts` in a `test/` folder next to the code (as `src/utils/queryParser/test/`, `src/composables/table/test/`). Pull logic out of components into composables or `utils` so it can be tested without mounting. `src/test/setup.ts` mocks Tauri's IPC for every test (`mockIPC` answering `undefined`); a test that needs real answers calls `mockIPC` with its own handler. - Rust: `#[cfg(test)] mod tests` in the file, `cargo test`. Abstract MongoDB and the keyring behind traits where a test needs to replace them. - Untested today, worth covering when touched: `formatCellValue`, `mergeColumnOrder` and the column sizing, `eventToKeyString` and `CommandRegistry`, `tabsStore`, `extractErrorMessage`, `abortableInvoke`; in Rust `TaskManager`, `DriverError::user_message`, `build_connection_string`, `FileRepository`. - `vue-tsc` type-checks the test files with `noUnusedLocals`, so an unused import in a test breaks `pnpm build`. diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index c9599ff..c95bddd 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -14,6 +14,7 @@ pub mod connection_handler; pub mod connector; pub mod database; pub mod drivers; +pub mod menu; pub mod task_manager; pub struct AppState { @@ -28,7 +29,13 @@ pub fn create_app_state(repository: impl ConnectorRepository + 'static) -> AppSt #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - tauri::Builder::default() + let mut builder = tauri::Builder::default(); + + if cfg!(target_os = "macos") { + builder = builder.menu(menu::macos_menu::); + } + + builder .plugin( tauri_plugin_log::Builder::new() .level(tauri_plugin_log::log::LevelFilter::Debug) diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs new file mode 100644 index 0000000..0ded4e8 --- /dev/null +++ b/src-tauri/src/menu.rs @@ -0,0 +1,66 @@ +use tauri::{ + menu::{AboutMetadata, Menu, PredefinedMenuItem, Submenu}, + AppHandle, Runtime, +}; + +/// Tauri's default macOS menu without "Close Window": its Cmd+W would close the app +/// instead of the active tab. The Edit menu stays, macOS routes copy and paste through it. +/// Compiled everywhere so a Linux build catches type errors, but only used on macOS. +pub fn macos_menu(app: &AppHandle) -> tauri::Result> { + let pkg_info = app.package_info(); + let about = AboutMetadata { + name: Some(pkg_info.name.clone()), + version: Some(pkg_info.version.to_string()), + ..Default::default() + }; + + Menu::with_items( + app, + &[ + &Submenu::with_items( + app, + pkg_info.name.clone(), + true, + &[ + &PredefinedMenuItem::about(app, None, Some(about))?, + &PredefinedMenuItem::separator(app)?, + &PredefinedMenuItem::services(app, None)?, + &PredefinedMenuItem::separator(app)?, + &PredefinedMenuItem::hide(app, None)?, + &PredefinedMenuItem::hide_others(app, None)?, + &PredefinedMenuItem::separator(app)?, + &PredefinedMenuItem::quit(app, None)?, + ], + )?, + &Submenu::with_items( + app, + "Edit", + true, + &[ + &PredefinedMenuItem::undo(app, None)?, + &PredefinedMenuItem::redo(app, None)?, + &PredefinedMenuItem::separator(app)?, + &PredefinedMenuItem::cut(app, None)?, + &PredefinedMenuItem::copy(app, None)?, + &PredefinedMenuItem::paste(app, None)?, + &PredefinedMenuItem::select_all(app, None)?, + ], + )?, + &Submenu::with_items( + app, + "View", + true, + &[&PredefinedMenuItem::fullscreen(app, None)?], + )?, + &Submenu::with_items( + app, + "Window", + true, + &[ + &PredefinedMenuItem::minimize(app, None)?, + &PredefinedMenuItem::maximize(app, None)?, + ], + )?, + ], + ) +} diff --git a/src/domains/shortcuts/config/default-binding.ts b/src/domains/shortcuts/config/default-binding.ts index c48a08a..ddbe89a 100644 --- a/src/domains/shortcuts/config/default-binding.ts +++ b/src/domains/shortcuts/config/default-binding.ts @@ -3,14 +3,14 @@ import { Commands, KeyBinding } from "../models"; export const DefaultBindings: KeyBinding[] = [ { commandId: Commands.TAB_CLOSE, - keyCode: "ctrl+w", + keyCode: "mod+w", }, { commandId: Commands.CONNECTION_DISCONNECT, - keyCode: "ctrl+shift+d", + keyCode: "mod+shift+d", }, { commandId: Commands.EVENT_EXECUTE, - keyCode: "ctrl+enter" + keyCode: "mod+enter" }, ]; diff --git a/src/domains/shortcuts/registry/CommandRegistry.ts b/src/domains/shortcuts/registry/CommandRegistry.ts index a8fafb8..09c11a3 100644 --- a/src/domains/shortcuts/registry/CommandRegistry.ts +++ b/src/domains/shortcuts/registry/CommandRegistry.ts @@ -56,7 +56,7 @@ export class CommandRegistry { if (!subs?.length) return; - const idx = subs.findIndex(subscriber); + const idx = subs.indexOf(subscriber); if (idx === -1) return; diff --git a/src/domains/shortcuts/test/CommandRegistry.test.ts b/src/domains/shortcuts/test/CommandRegistry.test.ts new file mode 100644 index 0000000..bcf84d0 --- /dev/null +++ b/src/domains/shortcuts/test/CommandRegistry.test.ts @@ -0,0 +1,81 @@ +import { describe, expect, it, vi } from "vitest"; +import { DefaultBindings, initCommands } from "../config"; +import { Commands } from "../models"; +import { CommandRegistry } from "../registry"; + +function registryWith(execute = vi.fn()) { + const registry = new CommandRegistry(); + registry.registerCommand({ id: Commands.TAB_CLOSE, name: "close", execute }); + return { registry, execute }; +} + +describe("CommandRegistry", () => { + it("runs a registered command and notifies its subscribers", () => { + const { registry, execute } = registryWith(); + const subscriber = vi.fn(); + registry.subscribe(Commands.TAB_CLOSE, subscriber); + + registry.executeCommand(Commands.TAB_CLOSE); + + expect(execute).toHaveBeenCalledOnce(); + expect(subscriber).toHaveBeenCalledOnce(); + }); + + it("ignores an unknown command", () => { + const { registry, execute } = registryWith(); + expect(() => registry.executeCommand("nope")).not.toThrow(); + expect(execute).not.toHaveBeenCalled(); + }); + + it("unsubscribes exactly the given subscriber without calling it", () => { + const { registry } = registryWith(); + const first = vi.fn(); + const second = vi.fn(); + registry.subscribe(Commands.TAB_CLOSE, first); + registry.subscribe(Commands.TAB_CLOSE, second); + + registry.unsubscribe(Commands.TAB_CLOSE, second); + expect(first).not.toHaveBeenCalled(); + expect(second).not.toHaveBeenCalled(); + + registry.executeCommand(Commands.TAB_CLOSE); + expect(first).toHaveBeenCalledOnce(); + expect(second).not.toHaveBeenCalled(); + }); + + it("does nothing when unsubscribing an unknown subscriber or event", () => { + const { registry } = registryWith(); + const subscriber = vi.fn(); + registry.subscribe(Commands.TAB_CLOSE, subscriber); + + registry.unsubscribe(Commands.TAB_CLOSE, vi.fn()); + registry.unsubscribe(Commands.EVENT_EXECUTE, subscriber); + + registry.executeCommand(Commands.TAB_CLOSE); + expect(subscriber).toHaveBeenCalledOnce(); + }); + + it("runs nothing while disabled", () => { + const { registry, execute } = registryWith(); + registry.disableExecution(); + registry.executeCommand(Commands.TAB_CLOSE); + expect(execute).not.toHaveBeenCalled(); + + registry.enableExecution(); + registry.executeCommand(Commands.TAB_CLOSE); + expect(execute).toHaveBeenCalledOnce(); + }); +}); + +describe("default bindings", () => { + it("bind every command that initCommands registers, with the mod key", () => { + const registry = new CommandRegistry(); + initCommands(registry, { tabsStore: {}, connectionStore: {} }); + + for (const binding of DefaultBindings) { + expect(registry.commands.has(binding.commandId)).toBe(true); + expect(binding.keyCode.startsWith("mod+")).toBe(true); + } + expect(DefaultBindings.map((b) => b.keyCode)).toEqual(["mod+w", "mod+shift+d", "mod+enter"]); + }); +}); diff --git a/src/domains/shortcuts/test/eventToKeyString.test.ts b/src/domains/shortcuts/test/eventToKeyString.test.ts new file mode 100644 index 0000000..d8950b3 --- /dev/null +++ b/src/domains/shortcuts/test/eventToKeyString.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; +import { eventToKeyString } from "../utils"; + +function key(key: string, mods: Partial> = {}) { + return { key, ctrlKey: false, metaKey: false, shiftKey: false, altKey: false, ...mods } as KeyboardEvent; +} + +describe("eventToKeyString", () => { + it("maps Ctrl to mod outside macOS", () => { + expect(eventToKeyString(key("w", { ctrlKey: true }), false)).toBe("mod+w"); + }); + + it("maps Cmd to mod on macOS", () => { + expect(eventToKeyString(key("w", { metaKey: true }), true)).toBe("mod+w"); + }); + + it("keeps Ctrl apart from mod on macOS", () => { + expect(eventToKeyString(key("w", { ctrlKey: true }), true)).toBe("ctrl+w"); + }); + + it("keeps the meta key apart from mod outside macOS", () => { + expect(eventToKeyString(key("w", { metaKey: true }), false)).toBe("meta+w"); + }); + + it("orders modifiers and lowercases the key", () => { + expect(eventToKeyString(key("D", { ctrlKey: true, shiftKey: true }), false)).toBe("mod+shift+d"); + expect(eventToKeyString(key("Enter", { ctrlKey: true, altKey: true, shiftKey: true }), false)).toBe("mod+shift+alt+enter"); + }); + + it("returns only the modifiers while a modifier key itself is pressed", () => { + expect(eventToKeyString(key("Control", { ctrlKey: true }), false)).toBe("mod"); + expect(eventToKeyString(key("Shift", { shiftKey: true }), false)).toBe("shift"); + expect(eventToKeyString(key("Meta", { metaKey: true }), true)).toBe("mod"); + }); + + it("returns the key alone without modifiers", () => { + expect(eventToKeyString(key("a"), false)).toBe("a"); + }); +}); diff --git a/src/domains/shortcuts/utils/eventToKeyString.ts b/src/domains/shortcuts/utils/eventToKeyString.ts index 5a7e6d2..138bcc0 100644 --- a/src/domains/shortcuts/utils/eventToKeyString.ts +++ b/src/domains/shortcuts/utils/eventToKeyString.ts @@ -1,10 +1,16 @@ -export function eventToKeyString(ev: KeyboardEvent): string { +export function isMacPlatform(): boolean { + return typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent); +} + +// "mod" is the platform's command key: Cmd on macOS, Ctrl everywhere else +export function eventToKeyString(ev: KeyboardEvent, isMac = isMacPlatform()): string { const parts: string[] = []; - if (ev.ctrlKey) parts.push("ctrl"); + if (isMac ? ev.metaKey : ev.ctrlKey) parts.push("mod"); + if (isMac && ev.ctrlKey) parts.push("ctrl"); + if (!isMac && ev.metaKey) parts.push("meta"); if (ev.shiftKey) parts.push("shift"); if (ev.altKey) parts.push("alt"); - if (ev.metaKey) parts.push("meta"); const key = ev.key.toLowerCase(); diff --git a/src/test/setup.ts b/src/test/setup.ts new file mode 100644 index 0000000..e9191d9 --- /dev/null +++ b/src/test/setup.ts @@ -0,0 +1,11 @@ +import { clearMocks, mockIPC } from "@tauri-apps/api/mocks"; +import { afterEach, beforeEach } from "vitest"; + +// the logger and stores call Tauri; tests that care about a command override this with their own mockIPC +beforeEach(() => { + mockIPC(() => undefined); +}); + +afterEach(() => { + clearMocks(); +}); diff --git a/vite.config.ts b/vite.config.ts index 8a7db6c..aa6e457 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,6 +19,7 @@ export default defineConfig(async () => ({ test: { environment: "happy-dom", + setupFiles: ["./src/test/setup.ts"], }, // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` From a7b4c1adfd5f521e9cb51106b26deb62c33846b2 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:50:47 +0100 Subject: [PATCH 10/33] refactor: credential store behind a trait the repository reached the keyring through a concrete CredentialService, and every command that needed a password downcast the repository to FileRepository to get at it; another repository type would have failed with "unsupported repository type". passwords now go through a CredentialStore trait, the repository offers get_password and hydrate, and the commands use those. hydrate_connection_with_credentials and the as_any downcasts are gone. the keyring store reports a missing entry as CredentialError::NotFound, so "no password stored" and "keyring broken" can be told apart. update now keeps the id of the path, not one sent in the body. the repository has its first tests: save, get, update with and without a new password, switching to no authentication, delete, a failing keyring, empty, corrupt and foreign-version files. they run on a temp directory with an in-memory credential store, never on the real keyring. 21 tests. --- CLAUDE.md | 7 +- src-tauri/Cargo.toml | 3 + src-tauri/src/connector/commands/error.rs | 3 + .../commands/get_connection_password.rs | 24 +- .../repositories/connector_repository.rs | 10 +- .../credentials/credential_service.rs | 54 +-- .../credentials/credential_store.rs | 86 +++++ .../hydrate_connection_with_credentials.rs | 17 - .../connector/repositories/credentials/mod.rs | 2 +- .../connector/repositories/file_repository.rs | 355 ++++++++++++++++-- .../src/database/commands/get_databases.rs | 16 +- .../src/database/commands/start_connect.rs | 29 +- .../database/commands/start_find_documents.rs | 29 +- src-tauri/src/lib.rs | 3 +- 14 files changed, 477 insertions(+), 161 deletions(-) create mode 100644 src-tauri/src/connector/repositories/credentials/credential_store.rs delete mode 100644 src-tauri/src/connector/repositories/credentials/hydrate_connection_with_credentials.rs diff --git a/CLAUDE.md b/CLAUDE.md index 1b48a3d..ae48124 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,7 +43,7 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt - One command per file in `/commands/.rs`, re-exported by its `mod.rs`. - Errors cross IPC as `{ kind, message, user_message }`: `DriverError` (drivers), `CommandError` (connector), `TaskError` (tasks). Each implements `Serialize` by hand. A new error variant needs a `user_message`, and the UI shows only that. - Slow work is a task: a `start_*` command passes its future to `TaskManager.spawn_task` and returns the id; the UI waits with `await_task_result` and cancels with `cancel_task`. The future returns `Result`, with errors serialized through `serde_json::to_value(&e)`. Follow `start_connect.rs`. -- Credentials: `get_connections`/`get_connection` never return a password. A command that talks to MongoDB loads it with `hydrate_connection_with_credentials` right before use. The only command that hands a password to the UI is `get_connection_password` (edit dialog). +- Credentials: `get_connections`/`get_connection` never return a password. A command that talks to MongoDB loads it with `ConnectorRepository::hydrate` right before use. The only command that hands a password to the UI is `get_connection_password` (edit dialog). Passwords go through the `CredentialStore` trait: `CredentialService` is the OS keyring, `MemoryCredentialStore` (tests only) keeps them in memory and can be told to fail. - `ConnectionHandler.get_or_connect` keeps one driver per connection id for the life of the process. Nothing removes it yet (see Gotchas). - `DatabaseDriver` is the seam for database work. Add a method to the trait, implement it in `MongoDbOfficialDriver`, then call it from a task command. - `connections.json` is `{ "version": 1, "connections": { "": … } }`. A change of the stored shape needs a new `STORAGE_VERSION` and a migration in `FileRepository.load_storage`; today a version mismatch is an error. @@ -71,7 +71,7 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt - Every piece of logic gets unit tests, for the regular cases and every edge case you can think of: empty and missing input, boundaries, wrong kinds of values, failing collaborators (MongoDB, keyring, file system). - Frontend: vitest in happy-dom (the `test` block of `vite.config.ts`), files `*.test.ts` in a `test/` folder next to the code (as `src/utils/queryParser/test/`, `src/composables/table/test/`). Pull logic out of components into composables or `utils` so it can be tested without mounting. `src/test/setup.ts` mocks Tauri's IPC for every test (`mockIPC` answering `undefined`); a test that needs real answers calls `mockIPC` with its own handler. -- Rust: `#[cfg(test)] mod tests` in the file, `cargo test`. Abstract MongoDB and the keyring behind traits where a test needs to replace them. +- Rust: `#[cfg(test)] mod tests` in the file, `cargo test`, async tests with `#[tokio::test]`. Abstract MongoDB and the keyring behind traits where a test needs to replace them. `file_repository.rs` shows the pattern: a `TempDir` per test and a `MemoryCredentialStore`. - Untested today, worth covering when touched: `formatCellValue`, `mergeColumnOrder` and the column sizing, `eventToKeyString` and `CommandRegistry`, `tabsStore`, `extractErrorMessage`, `abortableInvoke`; in Rust `TaskManager`, `DriverError::user_message`, `build_connection_string`, `FileRepository`. - `vue-tsc` type-checks the test files with `noUnusedLocals`, so an unused import in a test breaks `pnpm build`. - End-to-end checks are manual: `pnpm tauri dev` against a local MongoDB. @@ -104,11 +104,10 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt - The connection field `uri` holds a host. The driver always builds `mongodb://:/?authSource=`; SRV and full connection strings don't work. - TypeScript `ConnectionType.ShardedCluster` is `"SharedCluster"`, Rust expects `ShardedCluster`. Harmless only because the UI always sends `Standalone`. - `ConnectionServiceIPC.saveConnection`/`saveConnections` call commands that don't exist. `ConnectionRepositoryIPC` is registered and unused. -- Commands reach the keyring by downcasting the repository to `FileRepository`. Another repository type fails with "Unsupported repository type". - The log level is `Debug` in release builds too. `ConnectionDialog` logs form values, password included, at `trace`. - Query filters cross IPC as extended JSON. bson turns `{ $oid }`, `{ $date: "" }` and the number wrappers into BSON types; anything it can't read stays a plain object and silently matches nothing. - On Linux the keyring needs a Secret Service (GNOME Keyring, KWallet). keyring 4 talks to it through `zbus`; there is no keyutils cache any more. -- `cargo clippy` reports 15 warnings in code that predates the revival (needless borrows, missing `Default`, an 8-argument command, …). Fix them where you touch the code. +- `cargo clippy` reports 13 warnings in code that predates the revival (needless borrows, missing `Default`, an 8-argument command, …). Fix them where you touch the code. - Change the pinned pnpm with `pnpm self-update ` inside the repo, never by hand, or `--frozen-lockfile` fails (pnpm records its version in the lockfile). - `gh` is not installed on this machine. The repo is public: read issues and pull requests through `https://api.github.com/repos/WebXIO/monolens/issues` and `/pulls`. diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 44b07fa..b117bad 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -32,3 +32,6 @@ log = "0.4.35" tauri-plugin-log = "2" url = "2.5.8" keyring = "4.2.0" + +[dev-dependencies] +tokio = { version = "1.54.1", features = ["macros", "rt-multi-thread"] } diff --git a/src-tauri/src/connector/commands/error.rs b/src-tauri/src/connector/commands/error.rs index d1f47d4..a83d06a 100644 --- a/src-tauri/src/connector/commands/error.rs +++ b/src-tauri/src/connector/commands/error.rs @@ -72,6 +72,9 @@ pub enum RepositoryError { #[derive(Debug, Error)] pub enum CredentialError { + #[error("No password stored for connection {0}")] + NotFound(String), + #[error("Keyring error: {0}")] Keyring(#[from] keyring::Error), diff --git a/src-tauri/src/connector/commands/get_connection_password.rs b/src-tauri/src/connector/commands/get_connection_password.rs index 47f0515..52c31de 100644 --- a/src-tauri/src/connector/commands/get_connection_password.rs +++ b/src-tauri/src/connector/commands/get_connection_password.rs @@ -1,7 +1,6 @@ use tauri::State; use crate::connector::commands::error::CommandError; -use crate::connector::repositories::file_repository::FileRepository; use crate::AppState; #[tauri::command] @@ -9,21 +8,10 @@ pub async fn get_connection_password( state: State<'_, AppState>, id: String, ) -> Result, CommandError> { - let repository = &state.connection_repository; - - let file_repo = repository - .as_any() - .downcast_ref::() - .ok_or_else(|| { - CommandError::new( - "Unsupported repository type", - "repository", - "Could not retrieve password.", - ) - })?; - - match file_repo.credential_service.get_password(&id).await { - Ok(password) => Ok(Some(password)), - Err(_) => Ok(None), - } + // the edit dialog shows an empty field when the password can't be read + Ok(state + .connection_repository + .get_password(&id) + .await + .unwrap_or(None)) } diff --git a/src-tauri/src/connector/repositories/connector_repository.rs b/src-tauri/src/connector/repositories/connector_repository.rs index 32df29e..2fd0e9d 100644 --- a/src-tauri/src/connector/repositories/connector_repository.rs +++ b/src-tauri/src/connector/repositories/connector_repository.rs @@ -1,15 +1,11 @@ -use std::any::Any; - use async_trait::async_trait; use crate::connector::commands::error::RepositoryError; use crate::connector::models::create_connection::CreateConnection; use crate::connector::models::connection::Connection; -use crate::connector::repositories::storage_wrapper::ConnectionStorage; #[async_trait] pub trait ConnectorRepository: Send + Sync { - fn as_any(&self) -> &dyn Any; async fn list(&self) -> Result, RepositoryError>; async fn get(&self, id: &str) -> Result; async fn save( @@ -22,6 +18,8 @@ pub trait ConnectorRepository: Send + Sync { connection: &Connection, ) -> Result<(), RepositoryError>; async fn delete(&self, id: &str) -> Result<(), RepositoryError>; - async fn load_storage(&self) -> Result; - async fn write_storage(&self, storage: &ConnectionStorage) -> Result<(), RepositoryError>; + /// The stored password, `None` when there is none. + async fn get_password(&self, id: &str) -> Result, RepositoryError>; + /// The connection with its password filled in when it uses authentication. + async fn hydrate(&self, connection: &Connection) -> Result; } diff --git a/src-tauri/src/connector/repositories/credentials/credential_service.rs b/src-tauri/src/connector/repositories/credentials/credential_service.rs index fbfce93..4429251 100644 --- a/src-tauri/src/connector/repositories/credentials/credential_service.rs +++ b/src-tauri/src/connector/repositories/credentials/credential_service.rs @@ -1,7 +1,10 @@ +use async_trait::async_trait; use keyring::Entry; use crate::connector::commands::error::CredentialError; +use crate::connector::repositories::credentials::credential_store::CredentialStore; +/// Passwords in the OS keyring: Keychain, Credential Manager or Secret Service. pub struct CredentialService { service_name: String, } @@ -13,7 +16,21 @@ impl CredentialService { } } - pub async fn set_password( + fn get_key(&self, connection_id: &str) -> String { + format!("connection:{}:basic_password", connection_id) + } + + fn not_found(connection_id: &str, err: keyring::Error) -> CredentialError { + match err { + keyring::Error::NoEntry => CredentialError::NotFound(connection_id.to_string()), + other => CredentialError::Keyring(other), + } + } +} + +#[async_trait] +impl CredentialStore for CredentialService { + async fn set_password( &self, connection_id: &str, password: &str, @@ -22,6 +39,7 @@ impl CredentialService { let key = self.get_key(connection_id); let pass = password.to_string(); + // keyring calls block on the platform store tokio::task::spawn_blocking(move || { let entry = Entry::new(&service, &key)?; entry.set_password(&pass)?; @@ -32,39 +50,21 @@ impl CredentialService { Ok(()) } - pub async fn get_password( - &self, - connection_id: &str, - ) -> Result { + async fn get_password(&self, connection_id: &str) -> Result { let service = self.service_name.clone(); let key = self.get_key(connection_id); - let password = tokio::task::spawn_blocking(move || { - let entry = Entry::new(&service, &key)?; - entry.get_password() - }) - .await??; - - Ok(password) + tokio::task::spawn_blocking(move || Entry::new(&service, &key)?.get_password()) + .await? + .map_err(|e| Self::not_found(connection_id, e)) } - pub async fn delete_password( - &self, - connection_id: &str, - ) -> Result<(), CredentialError> { + async fn delete_password(&self, connection_id: &str) -> Result<(), CredentialError> { let service = self.service_name.clone(); let key = self.get_key(connection_id); - tokio::task::spawn_blocking(move || { - let entry = Entry::new(&service, &key)?; - entry.delete_credential() - }) - .await??; - - Ok(()) - } - - fn get_key(&self, connection_id: &str) -> String { - format!("connection:{}:basic_password", connection_id) + tokio::task::spawn_blocking(move || Entry::new(&service, &key)?.delete_credential()) + .await? + .map_err(|e| Self::not_found(connection_id, e)) } } diff --git a/src-tauri/src/connector/repositories/credentials/credential_store.rs b/src-tauri/src/connector/repositories/credentials/credential_store.rs new file mode 100644 index 0000000..9020a74 --- /dev/null +++ b/src-tauri/src/connector/repositories/credentials/credential_store.rs @@ -0,0 +1,86 @@ +use async_trait::async_trait; + +use crate::connector::commands::error::CredentialError; + +/// Where connection passwords live: the OS keyring in the app, memory in tests. +#[async_trait] +pub trait CredentialStore: Send + Sync { + async fn set_password(&self, connection_id: &str, password: &str) + -> Result<(), CredentialError>; + /// `CredentialError::NotFound` when nothing is stored for the connection. + async fn get_password(&self, connection_id: &str) -> Result; + async fn delete_password(&self, connection_id: &str) -> Result<(), CredentialError>; +} + +#[cfg(test)] +pub mod memory { + use std::collections::HashMap; + use std::sync::Mutex; + + use async_trait::async_trait; + + use super::CredentialStore; + use crate::connector::commands::error::CredentialError; + + #[derive(Default)] + pub struct MemoryCredentialStore { + passwords: Mutex>, + fail: Mutex, + } + + impl MemoryCredentialStore { + pub fn stored(&self, connection_id: &str) -> Option { + self.passwords.lock().unwrap().get(connection_id).cloned() + } + + pub fn insert(&self, connection_id: &str, password: &str) { + self.passwords + .lock() + .unwrap() + .insert(connection_id.to_string(), password.to_string()); + } + + /// Every following call fails like a locked or missing keyring would. + pub fn fail_from_now_on(&self) { + *self.fail.lock().unwrap() = true; + } + + fn check(&self) -> Result<(), CredentialError> { + if *self.fail.lock().unwrap() { + return Err(CredentialError::Keyring(keyring::Error::NoStorageAccess( + "test store fails".into(), + ))); + } + Ok(()) + } + } + + #[async_trait] + impl CredentialStore for MemoryCredentialStore { + async fn set_password( + &self, + connection_id: &str, + password: &str, + ) -> Result<(), CredentialError> { + self.check()?; + self.insert(connection_id, password); + Ok(()) + } + + async fn get_password(&self, connection_id: &str) -> Result { + self.check()?; + self.stored(connection_id) + .ok_or_else(|| CredentialError::NotFound(connection_id.to_string())) + } + + async fn delete_password(&self, connection_id: &str) -> Result<(), CredentialError> { + self.check()?; + self.passwords + .lock() + .unwrap() + .remove(connection_id) + .map(|_| ()) + .ok_or_else(|| CredentialError::NotFound(connection_id.to_string())) + } + } +} diff --git a/src-tauri/src/connector/repositories/credentials/hydrate_connection_with_credentials.rs b/src-tauri/src/connector/repositories/credentials/hydrate_connection_with_credentials.rs deleted file mode 100644 index 8aebc75..0000000 --- a/src-tauri/src/connector/repositories/credentials/hydrate_connection_with_credentials.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::{connector::{models::{authentication::AuthenticationKind, connection::Connection}, repositories::file_repository::FileRepository}, drivers::errors::DriverError}; - -pub async fn hydrate_connection_with_credentials( - repository: &FileRepository, - connection: &Connection, -) -> Result { - let mut c = connection.clone(); - if let AuthenticationKind::BASIC = c.authentication.kind { - let password = repository - .credential_service - .get_password(&c.id) - .await - .map_err(|_| DriverError::ConnectionFailed("Could not fetch credentials".into()))?; - c.authentication.password = Some(password); - } - Ok(c) -} \ No newline at end of file diff --git a/src-tauri/src/connector/repositories/credentials/mod.rs b/src-tauri/src/connector/repositories/credentials/mod.rs index 45a0f03..47feb60 100644 --- a/src-tauri/src/connector/repositories/credentials/mod.rs +++ b/src-tauri/src/connector/repositories/credentials/mod.rs @@ -1,2 +1,2 @@ pub mod credential_service; -pub mod hydrate_connection_with_credentials; \ No newline at end of file +pub mod credential_store; diff --git a/src-tauri/src/connector/repositories/file_repository.rs b/src-tauri/src/connector/repositories/file_repository.rs index 1edd23f..b49862e 100644 --- a/src-tauri/src/connector/repositories/file_repository.rs +++ b/src-tauri/src/connector/repositories/file_repository.rs @@ -1,37 +1,67 @@ -use std::any::Any; use std::path::PathBuf; +use std::sync::Arc; use async_trait::async_trait; use tokio::fs; -use crate::connector::commands::error::RepositoryError; +use crate::connector::commands::error::{CredentialError, RepositoryError}; use crate::connector::models::authentication::AuthenticationKind; use crate::connector::models::connection::Connection; use crate::connector::models::create_connection::CreateConnection; use crate::connector::repositories::connector_repository::ConnectorRepository; -use crate::connector::repositories::credentials::credential_service::CredentialService; +use crate::connector::repositories::credentials::credential_store::CredentialStore; use crate::connector::repositories::storage_wrapper::{ConnectionStorage, STORAGE_VERSION}; pub struct FileRepository { base_path: PathBuf, - pub credential_service: CredentialService, + credentials: Arc, } impl FileRepository { - pub fn new(base_path: PathBuf, credential_service: crate::connector::repositories::credentials::credential_service::CredentialService) -> Self { + pub fn new(base_path: PathBuf, credentials: Arc) -> Self { FileRepository { base_path: base_path.join("connections.json"), - credential_service, + credentials, } } + + async fn load_storage(&self) -> Result { + if !fs::try_exists(&self.base_path).await? { + return Ok(ConnectionStorage::new()); + } + + let content = fs::read_to_string(&self.base_path).await?; + + if content.trim().is_empty() { + return Ok(ConnectionStorage::new()); + } + + let storage: ConnectionStorage = serde_json::from_str(&content)?; + + if storage.version != STORAGE_VERSION { + return Err(RepositoryError::MigrationError { + from: storage.version, + to: STORAGE_VERSION, + }); + } + + Ok(storage) + } + + async fn write_storage(&self, storage: &ConnectionStorage) -> Result<(), RepositoryError> { + if let Some(parent) = self.base_path.parent() { + fs::create_dir_all(parent).await?; + } + + let json = serde_json::to_string_pretty(storage)?; + fs::write(&self.base_path, json).await?; + + Ok(()) + } } #[async_trait] impl ConnectorRepository for FileRepository { - fn as_any(&self) -> &dyn Any { - self - } - async fn list(&self) -> Result, RepositoryError> { let storage = self.load_storage().await?; Ok(storage.connections.values().cloned().collect()) @@ -47,10 +77,9 @@ impl ConnectorRepository for FileRepository { let new_connection = Connection::from(connection); if let Some(pass) = password { - self.credential_service + self.credentials .set_password(&new_connection.id, &pass) - .await - .map_err(|e| RepositoryError::Credential(e))?; + .await?; } storage @@ -87,19 +116,18 @@ impl ConnectorRepository for FileRepository { match connection.authentication.kind { AuthenticationKind::BASIC => { + // without a new password the stored one stays if let Some(password) = &connection.authentication.password { - self.credential_service - .set_password(id, password) - .await - .map_err(|e| RepositoryError::Credential(e))?; + self.credentials.set_password(id, password).await?; } } AuthenticationKind::NONE => { - let _ = self.credential_service.delete_password(id).await; + let _ = self.credentials.delete_password(id).await; } } let mut clean = connection.clone(); + clean.id = id.to_string(); clean.authentication.password = None; *existing = clean; @@ -116,44 +144,295 @@ impl ConnectorRepository for FileRepository { return Err(RepositoryError::NotFound(id.to_string())); } - let _ = self.credential_service.delete_password(id).await; + let _ = self.credentials.delete_password(id).await; self.write_storage(&storage).await?; Ok(()) } - async fn load_storage(&self) -> Result { - if !fs::try_exists(&self.base_path).await? { - return Ok(ConnectionStorage::new()); + async fn get_password(&self, id: &str) -> Result, RepositoryError> { + match self.credentials.get_password(id).await { + Ok(password) => Ok(Some(password)), + Err(CredentialError::NotFound(_)) => Ok(None), + Err(e) => Err(e.into()), } + } - let content = fs::read_to_string(&self.base_path).await?; + async fn hydrate(&self, connection: &Connection) -> Result { + let mut hydrated = connection.clone(); + if let AuthenticationKind::BASIC = hydrated.authentication.kind { + hydrated.authentication.password = + Some(self.credentials.get_password(&hydrated.id).await?); + } + Ok(hydrated) + } +} - if content.trim().is_empty() { - return Ok(ConnectionStorage::new()); +#[cfg(test)] +mod tests { + use super::*; + use crate::connector::models::authentication::AuthenticationOptions; + use crate::connector::models::connection::ConnectorKind; + use crate::connector::models::connection_type::ConnectionType; + use crate::connector::repositories::credentials::credential_store::memory::MemoryCredentialStore; + + /// A directory of its own per test, removed again when the test ends. + struct TempDir(PathBuf); + + impl TempDir { + fn new() -> Self { + let dir = std::env::temp_dir().join(format!("monolens-test-{}", uuid::Uuid::new_v4())); + std::fs::create_dir_all(&dir).unwrap(); + TempDir(dir) } - let storage: ConnectionStorage = serde_json::from_str(&content)?; + fn file(&self) -> PathBuf { + self.0.join("connections.json") + } + } - if storage.version != STORAGE_VERSION { - return Err(RepositoryError::MigrationError { - from: storage.version, - to: STORAGE_VERSION, - }); + impl Drop for TempDir { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); } + } - Ok(storage) + fn setup() -> (TempDir, Arc, FileRepository) { + let dir = TempDir::new(); + let store = Arc::new(MemoryCredentialStore::default()); + let repository = FileRepository::new(dir.0.clone(), store.clone()); + (dir, store, repository) } - async fn write_storage(&self, storage: &ConnectionStorage) -> Result<(), RepositoryError> { - if let Some(parent) = self.base_path.parent() { - fs::create_dir_all(parent).await?; + fn create(password: Option<&str>) -> CreateConnection { + CreateConnection { + name: "Local".into(), + uri: "localhost".into(), + port: 27017, + connector: ConnectorKind::MongoDb, + connection_type: ConnectionType::Standalone, + authentication: AuthenticationOptions { + kind: if password.is_some() { + AuthenticationKind::BASIC + } else { + AuthenticationKind::NONE + }, + username: password.map(|_| "root".to_string()), + password: password.map(String::from), + database: Some("admin".into()), + }, } + } - let json = serde_json::to_string_pretty(storage)?; - fs::write(&self.base_path, json).await?; + #[tokio::test] + async fn lists_nothing_without_a_file() { + let (_dir, _store, repository) = setup(); + assert!(repository.list().await.unwrap().is_empty()); + } - Ok(()) + #[tokio::test] + async fn lists_nothing_for_an_empty_file() { + let (dir, _store, repository) = setup(); + std::fs::write(dir.file(), " \n").unwrap(); + assert!(repository.list().await.unwrap().is_empty()); + } + + #[tokio::test] + async fn save_keeps_the_password_out_of_the_file() { + let (dir, store, repository) = setup(); + + let saved = repository.save(create(Some("s3cr3t"))).await.unwrap(); + + assert!(!saved.id.is_empty()); + assert_eq!(saved.authentication.password, None); + assert_eq!(store.stored(&saved.id).as_deref(), Some("s3cr3t")); + let file = std::fs::read_to_string(dir.file()).unwrap(); + assert!(!file.contains("s3cr3t")); + assert!(file.contains("\"version\": 1")); + assert_eq!(repository.get(&saved.id).await.unwrap().name, "Local"); + } + + #[tokio::test] + async fn save_without_authentication_stores_no_password() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + assert_eq!(store.stored(&saved.id), None); + } + + #[tokio::test] + async fn save_fails_when_the_keyring_fails_and_writes_nothing() { + let (dir, store, repository) = setup(); + store.fail_from_now_on(); + + let result = repository.save(create(Some("pw"))).await; + + assert!(matches!(result, Err(RepositoryError::Credential(_)))); + assert!(!dir.file().exists()); + } + + #[tokio::test] + async fn get_of_an_unknown_id_is_not_found() { + let (_dir, _store, repository) = setup(); + assert!(matches!( + repository.get("nope").await, + Err(RepositoryError::NotFound(id)) if id == "nope" + )); + } + + #[tokio::test] + async fn update_with_a_password_replaces_it() { + let (dir, store, repository) = setup(); + let saved = repository.save(create(Some("old"))).await.unwrap(); + + let mut changed = saved.clone(); + changed.name = "Renamed".into(); + changed.authentication.password = Some("new".into()); + repository.update(&saved.id, &changed).await.unwrap(); + + assert_eq!(store.stored(&saved.id).as_deref(), Some("new")); + assert_eq!(repository.get(&saved.id).await.unwrap().name, "Renamed"); + assert!(!std::fs::read_to_string(dir.file()).unwrap().contains("new\"")); + } + + #[tokio::test] + async fn update_without_a_password_keeps_the_stored_one() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(Some("old"))).await.unwrap(); + + repository.update(&saved.id, &saved).await.unwrap(); + + assert_eq!(store.stored(&saved.id).as_deref(), Some("old")); + } + + #[tokio::test] + async fn update_to_no_authentication_deletes_the_password() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(Some("old"))).await.unwrap(); + + let mut changed = saved.clone(); + changed.authentication.kind = AuthenticationKind::NONE; + repository.update(&saved.id, &changed).await.unwrap(); + + assert_eq!(store.stored(&saved.id), None); + } + + #[tokio::test] + async fn update_keeps_the_id_of_the_path() { + let (_dir, _store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + + let mut changed = saved.clone(); + changed.id = "something-else".into(); + repository.update(&saved.id, &changed).await.unwrap(); + + assert_eq!(repository.get(&saved.id).await.unwrap().id, saved.id); + } + + #[tokio::test] + async fn update_of_an_unknown_id_is_not_found() { + let (_dir, _store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + assert!(matches!( + repository.update("nope", &saved).await, + Err(RepositoryError::NotFound(_)) + )); + } + + #[tokio::test] + async fn delete_removes_connection_and_password() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(Some("pw"))).await.unwrap(); + + repository.delete(&saved.id).await.unwrap(); + + assert!(repository.list().await.unwrap().is_empty()); + assert_eq!(store.stored(&saved.id), None); + } + + #[tokio::test] + async fn delete_works_without_a_stored_password() { + let (_dir, _store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + repository.delete(&saved.id).await.unwrap(); + assert!(repository.list().await.unwrap().is_empty()); + } + + #[tokio::test] + async fn delete_of_an_unknown_id_is_not_found() { + let (_dir, _store, repository) = setup(); + assert!(matches!( + repository.delete("nope").await, + Err(RepositoryError::NotFound(_)) + )); + } + + #[tokio::test] + async fn get_password_is_none_when_nothing_is_stored() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + assert_eq!(repository.get_password(&saved.id).await.unwrap(), None); + + store.insert(&saved.id, "pw"); + assert_eq!(repository.get_password(&saved.id).await.unwrap().as_deref(), Some("pw")); + } + + #[tokio::test] + async fn get_password_reports_a_failing_keyring() { + let (_dir, store, repository) = setup(); + store.fail_from_now_on(); + assert!(matches!( + repository.get_password("x").await, + Err(RepositoryError::Credential(CredentialError::Keyring(_))) + )); + } + + #[tokio::test] + async fn hydrate_fills_the_password_for_basic_authentication() { + let (_dir, _store, repository) = setup(); + let saved = repository.save(create(Some("pw"))).await.unwrap(); + + let hydrated = repository.hydrate(&saved).await.unwrap(); + + assert_eq!(hydrated.authentication.password.as_deref(), Some("pw")); + } + + #[tokio::test] + async fn hydrate_leaves_connections_without_authentication_alone() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + store.fail_from_now_on(); + + let hydrated = repository.hydrate(&saved).await.unwrap(); + + assert_eq!(hydrated.authentication.password, None); + } + + #[tokio::test] + async fn hydrate_fails_when_the_password_is_missing() { + let (_dir, store, repository) = setup(); + let saved = repository.save(create(Some("pw"))).await.unwrap(); + store.fail_from_now_on(); + assert!(repository.hydrate(&saved).await.is_err()); + } + + #[tokio::test] + async fn a_file_of_another_version_is_refused() { + let (dir, _store, repository) = setup(); + std::fs::write(dir.file(), r#"{ "version": 99, "connections": {} }"#).unwrap(); + assert!(matches!( + repository.list().await, + Err(RepositoryError::MigrationError { from: 99, to: STORAGE_VERSION }) + )); + } + + #[tokio::test] + async fn a_corrupt_file_is_a_serialization_error() { + let (dir, _store, repository) = setup(); + std::fs::write(dir.file(), "{ not json").unwrap(); + assert!(matches!( + repository.list().await, + Err(RepositoryError::Serialization(_)) + )); } } diff --git a/src-tauri/src/database/commands/get_databases.rs b/src-tauri/src/database/commands/get_databases.rs index 966e659..ce2b82d 100644 --- a/src-tauri/src/database/commands/get_databases.rs +++ b/src-tauri/src/database/commands/get_databases.rs @@ -1,7 +1,5 @@ use crate::AppState; use crate::connection_handler::connection_handler::ConnectionHandler; -use crate::connector::repositories::credentials::hydrate_connection_with_credentials::hydrate_connection_with_credentials; -use crate::connector::repositories::file_repository::FileRepository; use crate::connector::models::connection::Connection; use crate::drivers::errors::DriverError; use tauri::State; @@ -12,15 +10,11 @@ pub async fn get_databases( app_state: State<'_, AppState>, connection: Connection, ) -> Result, DriverError> { - // get repository from AppState - let repository = &app_state.connection_repository; - - // hydrate_connection_with_credentials needs a concrete type - let hydrated_connection = if let Some(file_repo) = repository.as_any().downcast_ref::() { - hydrate_connection_with_credentials(file_repo, &connection).await? - } else { - return Err(DriverError::ConnectionFailed("Unsupported repository type".into())); - }; + let hydrated_connection = app_state + .connection_repository + .hydrate(&connection) + .await + .map_err(|_| DriverError::ConnectionFailed("Could not fetch credentials".into()))?; let driver_lock = connection_handler .get_or_connect(hydrated_connection) diff --git a/src-tauri/src/database/commands/start_connect.rs b/src-tauri/src/database/commands/start_connect.rs index ee011a2..72d50ca 100644 --- a/src-tauri/src/database/commands/start_connect.rs +++ b/src-tauri/src/database/commands/start_connect.rs @@ -1,13 +1,7 @@ use crate::{ AppState, connection_handler::connection_handler::ConnectionHandler, - connector::{ - models::{connection::Connection}, - repositories::{ - credentials::hydrate_connection_with_credentials::hydrate_connection_with_credentials, - file_repository::FileRepository - } - }, + connector::models::connection::Connection, drivers::{driver::DatabaseDriver, errors::DriverError}, task_manager::task_manager::TaskManager }; use std::sync::Arc; @@ -25,19 +19,16 @@ pub async fn start_connect( let app_state = app_handle.state::(); let connection_handler = app_handle.state::(); - let repository = &app_state.connection_repository; - - let hydrated_connection = - if let Some(file_repo) = repository.as_any().downcast_ref::() { - hydrate_connection_with_credentials(file_repo, &connection) - .await - .map_err(|e| serde_json::to_value(&e).unwrap_or_default())? - } else { - return Err(serde_json::to_value(&DriverError::ConnectionFailed( - "Unsupported repository type".into(), + let hydrated_connection = app_state + .connection_repository + .hydrate(&connection) + .await + .map_err(|_| { + serde_json::to_value(&DriverError::ConnectionFailed( + "Could not fetch credentials".into(), )) - .unwrap_or_default()); - }; + .unwrap_or_default() + })?; let driver_lock: Arc>> = connection_handler .get_or_connect(hydrated_connection) diff --git a/src-tauri/src/database/commands/start_find_documents.rs b/src-tauri/src/database/commands/start_find_documents.rs index 6861d06..72f28b2 100644 --- a/src-tauri/src/database/commands/start_find_documents.rs +++ b/src-tauri/src/database/commands/start_find_documents.rs @@ -1,13 +1,7 @@ use crate::{ AppState, connection_handler::connection_handler::ConnectionHandler, - connector::{ - models::{connection::Connection}, - repositories::{ - credentials::hydrate_connection_with_credentials::hydrate_connection_with_credentials, - file_repository::FileRepository - } - }, + connector::models::connection::Connection, drivers::{driver::DatabaseDriver, errors::DriverError}, task_manager::task_manager::TaskManager }; use std::sync::Arc; @@ -30,19 +24,16 @@ pub async fn start_find_documents( let app_state = app_handle.state::(); let connection_handler = app_handle.state::(); - let repository = &app_state.connection_repository; - - let hydrated_connection = - if let Some(file_repo) = repository.as_any().downcast_ref::() { - hydrate_connection_with_credentials(file_repo, &connection) - .await - .map_err(|e| serde_json::to_value(&e).unwrap_or_default())? - } else { - return Err(serde_json::to_value(&DriverError::ConnectionFailed( - "Unsupported repository type".into(), + let hydrated_connection = app_state + .connection_repository + .hydrate(&connection) + .await + .map_err(|_| { + serde_json::to_value(&DriverError::ConnectionFailed( + "Could not fetch credentials".into(), )) - .unwrap_or_default()); - }; + .unwrap_or_default() + })?; let driver_lock: Arc>> = connection_handler .get_or_connect(hydrated_connection) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index c95bddd..291ce7f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -7,6 +7,7 @@ use crate::{ }, connector::repositories::credentials::credential_service::CredentialService }; +use std::sync::Arc; use crate::task_manager::task_manager::TaskManager; @@ -46,7 +47,7 @@ pub fn run() { log::debug!("Load config from path {}", path.display()); - let repository = FileRepository::new(path, CredentialService::new("monolens-connections")); + let repository = FileRepository::new(path, Arc::new(CredentialService::new("monolens-connections"))); let state = create_app_state(repository); app.manage(state); From 5f6efaa0c04a3b7271785b848d1a4a8e332f0952 Mon Sep 17 00:00:00 2001 From: "Kilian J. Halwachs" Date: Tue, 3 Nov 2026 10:57:13 +0100 Subject: [PATCH 11/33] feat: connection strings and options in the connection model a connection was a host in a field called uri, a port and a connectiontype nothing read; the driver built mongodb://host:port by hand, so srv strings and every option of a connection string were out of reach, although the host field suggested mongodb+srv://. a connection now has a target, either host and port or a mongodb:// or mongodb+srv:// string, and options for host targets: tls, ca file, invalid certificates, replica set, server selection timeout. connectionType is gone. before a connection is stored it is checked, and credentials in a connection string move out: the username into the authentication, the password into the keyring; the stored string has no user info. a refusal says why, and the dialog shows that text. the driver gets ClientOptions instead of a string: the builder for a host, ClientOptions::parse for a connection string. the driver checks some options against the user info (an authMechanism needs a username), so the stored credentials go back into the string, encoded, right before it is parsed. the authentication database is the form's, else the string's authSource, else admin. the url crate is gone. connections.json becomes version 2. a version 1 file is migrated on the first load and kept next to it as connections.v1.json; a v1 "uri" that is a connection string becomes a string target with its password moved to the keyring. the ui sends host targets; fields for connection strings and the options follow with the dialog. tests: uri splitting, normalising, the migration, the repository with version 1 files, the client options of both modes. integration tests, skipped by default, connect to a real mongodb by host and by string and check that a wrong password is an authentication error; they passed against a mongo:8 container. --- CLAUDE.md | 10 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- .../connector/commands/create_connection.rs | 2 +- .../connector/commands/delete_connection.rs | 2 +- src-tauri/src/connector/commands/error.rs | 13 + .../src/connector/commands/get_connection.rs | 2 +- .../src/connector/commands/get_connections.rs | 2 +- .../connector/commands/update_connection.rs | 2 +- .../src/connector/models/authentication.rs | 4 +- src-tauri/src/connector/models/connection.rs | 55 ++-- .../src/connector/models/connection_type.rs | 9 - .../src/connector/models/create_connection.rs | 15 +- src-tauri/src/connector/models/mod.rs | 6 +- src-tauri/src/connector/models/normalize.rs | 132 ++++++++ src-tauri/src/connector/models/options.rs | 13 + src-tauri/src/connector/models/uri.rs | 137 ++++++++ .../connector/repositories/file_repository.rs | 138 ++++++++- .../src/connector/repositories/migrations.rs | 160 ++++++++++ src-tauri/src/connector/repositories/mod.rs | 1 + .../connector/repositories/storage_wrapper.rs | 11 +- src-tauri/src/drivers/client_options.rs | 292 ++++++++++++++++++ src-tauri/src/drivers/mod.rs | 1 + .../src/drivers/mongo_official_driver.rs | 146 +++++---- .../connection/ConnectionDialog.vue | 23 +- src/components/connection/ConnectionGrid.vue | 4 +- .../connections/models/connection-type.ts | 6 - src/domains/connections/models/connection.ts | 36 ++- src/domains/connections/models/index.ts | 1 - .../connections/test/connection.test.ts | 30 ++ 30 files changed, 1098 insertions(+), 159 deletions(-) delete mode 100644 src-tauri/src/connector/models/connection_type.rs create mode 100644 src-tauri/src/connector/models/normalize.rs create mode 100644 src-tauri/src/connector/models/options.rs create mode 100644 src-tauri/src/connector/models/uri.rs create mode 100644 src-tauri/src/connector/repositories/migrations.rs create mode 100644 src-tauri/src/drivers/client_options.rs delete mode 100644 src/domains/connections/models/connection-type.ts create mode 100644 src/domains/connections/test/connection.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index ae48124..3e700c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,8 @@ pnpm build # vue-tsc --noEmit (includes the tests), then vi pnpm tauri build # installers; runs pnpm build first cd src-tauri && cargo check -cd src-tauri && cargo test # no Rust tests exist yet +cd src-tauri && cargo test # unit tests +cd src-tauri && MONGODB_TEST_HOST=127.0.0.1 MONGODB_TEST_PORT=27017 MONGODB_TEST_USER=root MONGODB_TEST_PASSWORD=… cargo test -- --ignored # integration tests against a real MongoDB cd src-tauri && cargo clippy ``` @@ -46,7 +47,8 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt - Credentials: `get_connections`/`get_connection` never return a password. A command that talks to MongoDB loads it with `ConnectorRepository::hydrate` right before use. The only command that hands a password to the UI is `get_connection_password` (edit dialog). Passwords go through the `CredentialStore` trait: `CredentialService` is the OS keyring, `MemoryCredentialStore` (tests only) keeps them in memory and can be told to fail. - `ConnectionHandler.get_or_connect` keeps one driver per connection id for the life of the process. Nothing removes it yet (see Gotchas). - `DatabaseDriver` is the seam for database work. Add a method to the trait, implement it in `MongoDbOfficialDriver`, then call it from a task command. -- `connections.json` is `{ "version": 1, "connections": { "": … } }`. A change of the stored shape needs a new `STORAGE_VERSION` and a migration in `FileRepository.load_storage`; today a version mismatch is an error. +- `connections.json` is `{ "version": 2, "connections": { "": … } }`. A connection has a `target` (`{ "kind": "Host", host, port }` or `{ "kind": "Uri", uri }`) and `options` (TLS, CA file, invalid certificates, replica set, server selection timeout; host targets only). A change of the stored shape needs a new `STORAGE_VERSION` and a migration in `repositories/migrations.rs`, called from `FileRepository.load_storage`, which keeps the old file as `connections.v.json`. +- Before storing, `models/normalize.rs` checks a connection and moves credentials out of a connection string (`models/uri.rs`); a refusal is `RepositoryError::Invalid`, whose text the UI shows. `drivers/client_options.rs` builds the driver's `ClientOptions`: the builder for a host, `ClientOptions::parse` for a string, with the user info put back in just before parsing. ### Frontend (`src`) @@ -101,13 +103,11 @@ Needs Rust and the Tauri prerequisites (`README.md`); on Ubuntu 26.04 `sudo apt - The driver pool never drops a driver. After a failed connect or an edited connection, the old MongoDB client stays until restart. Disconnect in the UI only resets frontend state. - `TabsContainer` keys each tab's view by the *active* tab id, so views multiply and run duplicate queries. `Ctrl+Enter` runs in every mounted view (issue #42), and `CommandRegistry.unsubscribe` uses `findIndex(subscriber)`, which calls the subscriber. Details in `docs/features/tabs.md` and `shortcuts.md`. - `TabViewQuery` queries `connectionStore.activeConnection`, not the tab's own connection, and tabs survive a switch of connection. -- The connection field `uri` holds a host. The driver always builds `mongodb://:/?authSource=`; SRV and full connection strings don't work. -- TypeScript `ConnectionType.ShardedCluster` is `"SharedCluster"`, Rust expects `ShardedCluster`. Harmless only because the UI always sends `Standalone`. - `ConnectionServiceIPC.saveConnection`/`saveConnections` call commands that don't exist. `ConnectionRepositoryIPC` is registered and unused. - The log level is `Debug` in release builds too. `ConnectionDialog` logs form values, password included, at `trace`. - Query filters cross IPC as extended JSON. bson turns `{ $oid }`, `{ $date: "" }` and the number wrappers into BSON types; anything it can't read stays a plain object and silently matches nothing. - On Linux the keyring needs a Secret Service (GNOME Keyring, KWallet). keyring 4 talks to it through `zbus`; there is no keyutils cache any more. -- `cargo clippy` reports 13 warnings in code that predates the revival (needless borrows, missing `Default`, an 8-argument command, …). Fix them where you touch the code. +- `cargo clippy` reports 12 warnings in code that predates the revival (needless borrows, missing `Default`, an 8-argument command, …). Fix them where you touch the code. - Change the pinned pnpm with `pnpm self-update ` inside the repo, never by hand, or `--frozen-lockfile` fails (pnpm records its version in the lockfile). - `gh` is not installed on this machine. The repo is public: read issues and pull requests through `https://api.github.com/repos/WebXIO/monolens/issues` and `/pulls`. diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b8a6f0d..fd39a4b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2722,6 +2722,7 @@ dependencies = [ "keyring", "log", "mongodb", + "percent-encoding", "serde", "serde_json", "tauri", @@ -2730,7 +2731,6 @@ dependencies = [ "tauri-plugin-opener", "thiserror 2.0.21", "tokio", - "url", "uuid", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b117bad..f1eb2ab 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -30,7 +30,7 @@ async-trait = "0.1.92" thiserror = "2.0.21" log = "0.4.35" tauri-plugin-log = "2" -url = "2.5.8" +percent-encoding = "2.3.2" keyring = "4.2.0" [dev-dependencies] diff --git a/src-tauri/src/connector/commands/create_connection.rs b/src-tauri/src/connector/commands/create_connection.rs index 0f43423..b3947c3 100644 --- a/src-tauri/src/connector/commands/create_connection.rs +++ b/src-tauri/src/connector/commands/create_connection.rs @@ -14,5 +14,5 @@ pub async fn create_connection( .connection_repository .save(connection) .await - .map_err(|e| CommandError::new(e.to_string(), "repository", "Failed to create connection.")) + .map_err(|e| CommandError::from_repository(e, "Failed to create connection.")) } diff --git a/src-tauri/src/connector/commands/delete_connection.rs b/src-tauri/src/connector/commands/delete_connection.rs index aa281bf..c354d5c 100644 --- a/src-tauri/src/connector/commands/delete_connection.rs +++ b/src-tauri/src/connector/commands/delete_connection.rs @@ -9,5 +9,5 @@ pub async fn delete_connection(state: State<'_, AppState>, id: String) -> Result .connection_repository .delete(&id) .await - .map_err(|e| CommandError::new(e.to_string(), "repository", "Failed to delete connection.")) + .map_err(|e| CommandError::from_repository(e, "Failed to delete connection.")) } diff --git a/src-tauri/src/connector/commands/error.rs b/src-tauri/src/connector/commands/error.rs index a83d06a..cb0fec2 100644 --- a/src-tauri/src/connector/commands/error.rs +++ b/src-tauri/src/connector/commands/error.rs @@ -22,6 +22,16 @@ impl CommandError { } } +impl CommandError { + /// A connection that fails validation tells the user why; other failures get `user_message`. + pub fn from_repository(err: RepositoryError, user_message: &str) -> Self { + match err { + RepositoryError::Invalid(message) => CommandError::new(message.clone(), "invalid", message), + other => CommandError::new(other.to_string(), "repository", user_message), + } + } +} + impl From for CommandError { fn from(err: std::io::Error) -> Self { CommandError { @@ -57,6 +67,9 @@ pub enum RepositoryError { #[error("Connection not found: {0}")] NotFound(String), + #[error("{0}")] + Invalid(String), + #[error("IO error: {0}")] Io(#[from] std::io::Error), diff --git a/src-tauri/src/connector/commands/get_connection.rs b/src-tauri/src/connector/commands/get_connection.rs index fac6ac7..557cf02 100644 --- a/src-tauri/src/connector/commands/get_connection.rs +++ b/src-tauri/src/connector/commands/get_connection.rs @@ -13,5 +13,5 @@ pub async fn get_connection( .connection_repository .get(&id) .await - .map_err(|e| CommandError::new(e.to_string(), "repository", "Failed to load connection.")) + .map_err(|e| CommandError::from_repository(e, "Failed to load connection.")) } diff --git a/src-tauri/src/connector/commands/get_connections.rs b/src-tauri/src/connector/commands/get_connections.rs index 3577003..32b6e86 100644 --- a/src-tauri/src/connector/commands/get_connections.rs +++ b/src-tauri/src/connector/commands/get_connections.rs @@ -10,5 +10,5 @@ pub async fn get_connections(state: State<'_, AppState>) -> Result, diff --git a/src-tauri/src/connector/models/connection.rs b/src-tauri/src/connector/models/connection.rs index b7dd6d2..1d25c73 100644 --- a/src-tauri/src/connector/models/connection.rs +++ b/src-tauri/src/connector/models/connection.rs @@ -1,39 +1,35 @@ use serde::{Deserialize, Serialize}; use crate::connector::models::{ - authentication::AuthenticationOptions, connection_type::ConnectionType, create_connection::CreateConnection, + authentication::AuthenticationOptions, create_connection::CreateConnection, + options::ConnectionOptions, }; use uuid::Uuid; -#[derive(Serialize, Debug, Deserialize, Clone)] +#[derive(Serialize, Debug, Deserialize, Clone, PartialEq)] pub enum ConnectorKind { MongoDb, } +/// Where the server is: host and port with option fields, or a connection string. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "kind")] +pub enum ConnectionTarget { + Host { host: String, port: u16 }, + /// `mongodb://` or `mongodb+srv://`, stored without user info + Uri { uri: String }, +} + #[derive(Serialize, Debug, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct Connection { pub id: String, pub name: String, - pub uri: String, - pub port: u16, pub connector: ConnectorKind, - pub connection_type: ConnectionType, + pub target: ConnectionTarget, pub authentication: AuthenticationOptions, -} - -impl Default for Connection { - fn default() -> Self { - Connection { - id: Uuid::new_v4().to_string(), - name: String::new(), - uri: String::new(), - port: 27017, - connector: ConnectorKind::MongoDb, - connection_type: ConnectionType::Standalone, - authentication: AuthenticationOptions::default(), - } - } + #[serde(default)] + pub options: ConnectionOptions, } impl From for Connection { @@ -41,25 +37,10 @@ impl From for Connection { Connection { id: Uuid::new_v4().to_string(), name: entity.name, - uri: entity.uri, - authentication: entity.authentication, - connection_type: entity.connection_type, connector: entity.connector, - port: entity.port - } - } -} - -impl Connection { - pub fn new(value: Connection) -> Self { - Connection { - id: Uuid::new_v4().to_string(), - name: value.name, - uri: value.uri, - port: value.port, - connector: value.connector, - connection_type: value.connection_type, - authentication: value.authentication, + target: entity.target, + authentication: entity.authentication, + options: entity.options, } } } diff --git a/src-tauri/src/connector/models/connection_type.rs b/src-tauri/src/connector/models/connection_type.rs deleted file mode 100644 index eb8f53c..0000000 --- a/src-tauri/src/connector/models/connection_type.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub enum ConnectionType { - Standalone, - ReplicaSet, - ShardedCluster, - DnsSeedList, -} diff --git a/src-tauri/src/connector/models/create_connection.rs b/src-tauri/src/connector/models/create_connection.rs index a332385..cf43990 100644 --- a/src-tauri/src/connector/models/create_connection.rs +++ b/src-tauri/src/connector/models/create_connection.rs @@ -1,15 +1,18 @@ use serde::{Deserialize, Serialize}; -use crate::connector::models::{authentication::AuthenticationOptions, connection::ConnectorKind, connection_type::ConnectionType}; - +use crate::connector::models::{ + authentication::AuthenticationOptions, + connection::{ConnectionTarget, ConnectorKind}, + options::ConnectionOptions, +}; #[derive(Serialize, Debug, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct CreateConnection { pub name: String, - pub uri: String, - pub port: u16, pub connector: ConnectorKind, - pub connection_type: ConnectionType, + pub target: ConnectionTarget, pub authentication: AuthenticationOptions, -} \ No newline at end of file + #[serde(default)] + pub options: ConnectionOptions, +} diff --git a/src-tauri/src/connector/models/mod.rs b/src-tauri/src/connector/models/mod.rs index e75a511..6d0f3c2 100644 --- a/src-tauri/src/connector/models/mod.rs +++ b/src-tauri/src/connector/models/mod.rs @@ -1,4 +1,6 @@ pub mod authentication; pub mod connection; -pub mod connection_type; -pub mod create_connection; \ No newline at end of file +pub mod create_connection; +pub mod normalize; +pub mod options; +pub mod uri; diff --git a/src-tauri/src/connector/models/normalize.rs b/src-tauri/src/connector/models/normalize.rs new file mode 100644 index 0000000..c8c5266 --- /dev/null +++ b/src-tauri/src/connector/models/normalize.rs @@ -0,0 +1,132 @@ +use crate::connector::models::{ + authentication::{AuthenticationKind, AuthenticationOptions}, + connection::ConnectionTarget, + uri::{is_connection_string, split_uri_credentials}, +}; + +/// Checks a connection before it is stored and moves credentials out of a connection string: +/// the username into the authentication, the password to where the repository keeps passwords. +/// Credentials typed into the form win over the ones in the string. +pub fn normalize( + name: &str, + target: ConnectionTarget, + mut auth: AuthenticationOptions, +) -> Result<(ConnectionTarget, AuthenticationOptions), String> { + if name.trim().is_empty() { + return Err(String::from("The connection needs a name.")); + } + + let target = match target { + ConnectionTarget::Host { host, port } => { + let host = host.trim().to_string(); + if host.is_empty() { + return Err(String::from("The connection needs a host.")); + } + if is_connection_string(&host) || host.contains("://") { + return Err(String::from( + "Enter mongodb:// and mongodb+srv:// addresses as a connection string, not as a host.", + )); + } + if port == 0 { + return Err(String::from("The port must be between 1 and 65535.")); + } + ConnectionTarget::Host { host, port } + } + ConnectionTarget::Uri { uri } => { + let split = split_uri_credentials(uri.trim())?; + if split.username.is_some() || split.password.is_some() { + auth.kind = AuthenticationKind::BASIC; + } + if auth.username.as_deref().unwrap_or("").is_empty() { + if let Some(username) = split.username { + auth.username = Some(username); + } + } + if auth.password.is_none() { + auth.password = split.password; + } + ConnectionTarget::Uri { uri: split.uri } + } + }; + + if auth.kind == AuthenticationKind::BASIC + && auth.username.as_deref().unwrap_or("").trim().is_empty() + { + return Err(String::from("Authentication needs a username.")); + } + + Ok((target, auth)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn none() -> AuthenticationOptions { + AuthenticationOptions::default() + } + + fn basic(username: &str, password: Option<&str>) -> AuthenticationOptions { + AuthenticationOptions { + kind: AuthenticationKind::BASIC, + username: Some(username.into()), + password: password.map(String::from), + database: None, + } + } + + fn uri(value: &str) -> ConnectionTarget { + ConnectionTarget::Uri { uri: value.into() } + } + + #[test] + fn trims_a_host() { + let (target, _) = normalize("Local", ConnectionTarget::Host { host: " localhost ".into(), port: 27017 }, none()).unwrap(); + assert_eq!(target, ConnectionTarget::Host { host: "localhost".into(), port: 27017 }); + } + + #[test] + fn refuses_a_missing_name_host_or_port() { + assert!(normalize(" ", ConnectionTarget::Host { host: "h".into(), port: 1 }, none()).is_err()); + assert!(normalize("n", ConnectionTarget::Host { host: " ".into(), port: 1 }, none()).is_err()); + assert!(normalize("n", ConnectionTarget::Host { host: "h".into(), port: 0 }, none()).is_err()); + } + + #[test] + fn refuses_a_connection_string_in_the_host_field() { + let err = normalize("n", ConnectionTarget::Host { host: "mongodb+srv://c.example.net".into(), port: 27017 }, none()).unwrap_err(); + assert!(err.contains("connection string")); + } + + #[test] + fn refuses_basic_authentication_without_username() { + assert!(normalize("n", ConnectionTarget::Host { host: "h".into(), port: 1 }, basic(" ", Some("pw"))).is_err()); + } + + #[test] + fn moves_credentials_out_of_a_connection_string() { + let (target, auth) = normalize("n", uri("mongodb://ada:pw@h1,h2/?replicaSet=rs"), none()).unwrap(); + assert_eq!(target, uri("mongodb://h1,h2/?replicaSet=rs")); + assert_eq!(auth.kind, AuthenticationKind::BASIC); + assert_eq!(auth.username.as_deref(), Some("ada")); + assert_eq!(auth.password.as_deref(), Some("pw")); + } + + #[test] + fn typed_credentials_win_over_the_string() { + let (_, auth) = normalize("n", uri("mongodb://ada:pw@h"), basic("bob", Some("typed"))).unwrap(); + assert_eq!(auth.username.as_deref(), Some("bob")); + assert_eq!(auth.password.as_deref(), Some("typed")); + } + + #[test] + fn a_string_without_credentials_keeps_the_authentication() { + let (_, auth) = normalize("n", uri("mongodb://h"), none()).unwrap(); + assert_eq!(auth, none()); + } + + #[test] + fn refuses_a_string_with_another_scheme() { + assert!(normalize("n", uri("http://h"), none()).is_err()); + } +} diff --git a/src-tauri/src/connector/models/options.rs b/src-tauri/src/connector/models/options.rs new file mode 100644 index 0000000..ec0c357 --- /dev/null +++ b/src-tauri/src/connector/models/options.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +/// Settings for a connection by host and port. A connection string carries its own. +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] +#[serde(rename_all = "camelCase", default)] +pub struct ConnectionOptions { + pub tls: bool, + pub tls_ca_file: Option, + pub tls_allow_invalid_certificates: bool, + pub replica_set: Option, + /// `None` means the driver's default (30 s) + pub server_selection_timeout_secs: Option, +} diff --git a/src-tauri/src/connector/models/uri.rs b/src-tauri/src/connector/models/uri.rs new file mode 100644 index 0000000..0e372e3 --- /dev/null +++ b/src-tauri/src/connector/models/uri.rs @@ -0,0 +1,137 @@ +use percent_encoding::percent_decode_str; + +const SCHEMES: [&str; 2] = ["mongodb://", "mongodb+srv://"]; + +/// A connection string split into the string without user info and the credentials it carried. +#[derive(Debug, PartialEq)] +pub struct UriCredentials { + pub uri: String, + pub username: Option, + pub password: Option, +} + +pub fn is_connection_string(value: &str) -> bool { + SCHEMES.iter().any(|scheme| value.starts_with(scheme)) +} + +/// Takes `user:password@` out of a connection string and percent-decodes both. +/// The hosts, the path and the options stay as they are. +pub fn split_uri_credentials(value: &str) -> Result { + let scheme = SCHEMES + .iter() + .find(|scheme| value.starts_with(*scheme)) + .ok_or_else(|| String::from("A connection string starts with mongodb:// or mongodb+srv://"))?; + + let rest = &value[scheme.len()..]; + let authority_end = rest.find(['/', '?']).unwrap_or(rest.len()); + let authority = &rest[..authority_end]; + + // the last @ ends the user info, an @ in a password must be percent-encoded anyway + let (user_info, hosts) = match authority.rfind('@') { + Some(at) => (Some(&authority[..at]), &authority[at + 1..]), + None => (None, authority), + }; + + if hosts.is_empty() { + return Err(String::from("The connection string names no host")); + } + + let decode = |part: &str| { + percent_decode_str(part) + .decode_utf8() + .map(|decoded| decoded.into_owned()) + .map_err(|_| String::from("The credentials in the connection string are not valid UTF-8")) + }; + + let (username, password) = match user_info { + None => (None, None), + Some(info) => match info.split_once(':') { + Some((user, pass)) => (Some(decode(user)?), Some(decode(pass)?)), + None => (Some(decode(info)?), None), + }, + }; + + Ok(UriCredentials { + uri: format!("{scheme}{hosts}{}", &rest[authority_end..]), + username: username.filter(|u| !u.is_empty()), + password, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn recognises_both_schemes() { + assert!(is_connection_string("mongodb://localhost")); + assert!(is_connection_string("mongodb+srv://cluster0.example.net")); + assert!(!is_connection_string("localhost")); + assert!(!is_connection_string("http://localhost")); + assert!(!is_connection_string("")); + } + + #[test] + fn leaves_a_string_without_user_info_alone() { + let split = split_uri_credentials("mongodb://localhost:27017/?replicaSet=rs0").unwrap(); + assert_eq!( + split, + UriCredentials { uri: "mongodb://localhost:27017/?replicaSet=rs0".into(), username: None, password: None } + ); + } + + #[test] + fn takes_user_and_password_out() { + let split = split_uri_credentials("mongodb+srv://ada:s3cr3t@cluster0.example.net/shop?retryWrites=true").unwrap(); + assert_eq!(split.uri, "mongodb+srv://cluster0.example.net/shop?retryWrites=true"); + assert_eq!(split.username.as_deref(), Some("ada")); + assert_eq!(split.password.as_deref(), Some("s3cr3t")); + } + + #[test] + fn decodes_percent_encoded_credentials() { + let split = split_uri_credentials("mongodb://us%40er:p%3Ass%40w%2Frd@db1:27017,db2:27018/?authSource=admin").unwrap(); + assert_eq!(split.uri, "mongodb://db1:27017,db2:27018/?authSource=admin"); + assert_eq!(split.username.as_deref(), Some("us@er")); + assert_eq!(split.password.as_deref(), Some("p:ss@w/rd")); + } + + #[test] + fn takes_a_user_without_password_out() { + let split = split_uri_credentials("mongodb://ada@localhost").unwrap(); + assert_eq!(split.uri, "mongodb://localhost"); + assert_eq!(split.username.as_deref(), Some("ada")); + assert_eq!(split.password, None); + } + + #[test] + fn keeps_an_empty_password() { + let split = split_uri_credentials("mongodb://ada:@localhost").unwrap(); + assert_eq!(split.password.as_deref(), Some("")); + } + + #[test] + fn handles_a_string_that_ends_after_the_host() { + let split = split_uri_credentials("mongodb://u:p@localhost").unwrap(); + assert_eq!(split.uri, "mongodb://localhost"); + } + + #[test] + fn an_at_in_the_options_is_not_user_info() { + let split = split_uri_credentials("mongodb://localhost/?appName=a@b").unwrap(); + assert_eq!(split.uri, "mongodb://localhost/?appName=a@b"); + assert_eq!(split.username, None); + } + + #[test] + fn refuses_other_schemes_and_missing_hosts() { + assert!(split_uri_credentials("localhost:27017").is_err()); + assert!(split_uri_credentials("mongodb://").is_err()); + assert!(split_uri_credentials("mongodb://user:pw@/db").is_err()); + } + + #[test] + fn refuses_credentials_that_are_not_utf8() { + assert!(split_uri_credentials("mongodb://%FF:pw@localhost").is_err()); + } +} diff --git a/src-tauri/src/connector/repositories/file_repository.rs b/src-tauri/src/connector/repositories/file_repository.rs index b49862e..a5494e0 100644 --- a/src-tauri/src/connector/repositories/file_repository.rs +++ b/src-tauri/src/connector/repositories/file_repository.rs @@ -8,8 +8,10 @@ use crate::connector::commands::error::{CredentialError, RepositoryError}; use crate::connector::models::authentication::AuthenticationKind; use crate::connector::models::connection::Connection; use crate::connector::models::create_connection::CreateConnection; +use crate::connector::models::normalize::normalize; use crate::connector::repositories::connector_repository::ConnectorRepository; use crate::connector::repositories::credentials::credential_store::CredentialStore; +use crate::connector::repositories::migrations::migrate_v1; use crate::connector::repositories::storage_wrapper::{ConnectionStorage, STORAGE_VERSION}; pub struct FileRepository { @@ -36,14 +38,36 @@ impl FileRepository { return Ok(ConnectionStorage::new()); } - let storage: ConnectionStorage = serde_json::from_str(&content)?; + let value: serde_json::Value = serde_json::from_str(&content)?; + let version = value.get("version").and_then(serde_json::Value::as_u64); - if storage.version != STORAGE_VERSION { - return Err(RepositoryError::MigrationError { - from: storage.version, + match version { + Some(v) if v == u64::from(STORAGE_VERSION) => Ok(serde_json::from_value(value)?), + Some(1) => self.migrate_from_v1(&content, &value).await, + other => Err(RepositoryError::MigrationError { + from: other.and_then(|v| u32::try_from(v).ok()).unwrap_or(0), to: STORAGE_VERSION, - }); + }), } + } + + async fn migrate_from_v1( + &self, + content: &str, + value: &serde_json::Value, + ) -> Result { + let (storage, moved) = migrate_v1(value)?; + + for password in moved { + self.credentials + .set_password(&password.connection_id, &password.password) + .await?; + } + + // the old file stays next to the new one, in case the migration loses something + fs::write(self.base_path.with_file_name("connections.v1.json"), content).await?; + self.write_storage(&storage).await?; + log::info!("Migrated connections.json from version 1 to {}", STORAGE_VERSION); Ok(storage) } @@ -73,6 +97,12 @@ impl ConnectorRepository for FileRepository { ) -> Result { let mut storage = self.load_storage().await?; + let (target, authentication) = + normalize(&connection.name, connection.target, connection.authentication) + .map_err(RepositoryError::Invalid)?; + connection.target = target; + connection.authentication = authentication; + let password = connection.authentication.password.take(); let new_connection = Connection::from(connection); @@ -114,6 +144,16 @@ impl ConnectorRepository for FileRepository { .get_mut(id) .ok_or_else(|| RepositoryError::NotFound(id.to_string()))?; + let (target, authentication) = normalize( + &connection.name, + connection.target.clone(), + connection.authentication.clone(), + ) + .map_err(RepositoryError::Invalid)?; + let mut connection = connection.clone(); + connection.target = target; + connection.authentication = authentication; + match connection.authentication.kind { AuthenticationKind::BASIC => { // without a new password the stored one stays @@ -126,7 +166,7 @@ impl ConnectorRepository for FileRepository { } } - let mut clean = connection.clone(); + let mut clean = connection; clean.id = id.to_string(); clean.authentication.password = None; @@ -173,8 +213,8 @@ impl ConnectorRepository for FileRepository { mod tests { use super::*; use crate::connector::models::authentication::AuthenticationOptions; - use crate::connector::models::connection::ConnectorKind; - use crate::connector::models::connection_type::ConnectionType; + use crate::connector::models::connection::{ConnectionTarget, ConnectorKind}; + use crate::connector::models::options::ConnectionOptions; use crate::connector::repositories::credentials::credential_store::memory::MemoryCredentialStore; /// A directory of its own per test, removed again when the test ends. @@ -208,10 +248,9 @@ mod tests { fn create(password: Option<&str>) -> CreateConnection { CreateConnection { name: "Local".into(), - uri: "localhost".into(), - port: 27017, connector: ConnectorKind::MongoDb, - connection_type: ConnectionType::Standalone, + target: ConnectionTarget::Host { host: "localhost".into(), port: 27017 }, + options: ConnectionOptions::default(), authentication: AuthenticationOptions { kind: if password.is_some() { AuthenticationKind::BASIC @@ -249,7 +288,7 @@ mod tests { assert_eq!(store.stored(&saved.id).as_deref(), Some("s3cr3t")); let file = std::fs::read_to_string(dir.file()).unwrap(); assert!(!file.contains("s3cr3t")); - assert!(file.contains("\"version\": 1")); + assert!(file.contains("\"version\": 2")); assert_eq!(repository.get(&saved.id).await.unwrap().name, "Local"); } @@ -435,4 +474,79 @@ mod tests { Err(RepositoryError::Serialization(_)) )); } + + #[tokio::test] + async fn save_moves_credentials_out_of_a_connection_string() { + let (dir, store, repository) = setup(); + let mut connection = create(None); + connection.target = ConnectionTarget::Uri { uri: "mongodb://ada:s3cr3t@h1,h2/?replicaSet=rs".into() }; + + let saved = repository.save(connection).await.unwrap(); + + assert_eq!(saved.target, ConnectionTarget::Uri { uri: "mongodb://h1,h2/?replicaSet=rs".into() }); + assert_eq!(saved.authentication.kind, AuthenticationKind::BASIC); + assert_eq!(saved.authentication.username.as_deref(), Some("ada")); + assert_eq!(store.stored(&saved.id).as_deref(), Some("s3cr3t")); + assert!(!std::fs::read_to_string(dir.file()).unwrap().contains("s3cr3t")); + } + + #[tokio::test] + async fn save_refuses_an_invalid_connection_with_its_reason() { + let (dir, _store, repository) = setup(); + let mut connection = create(None); + connection.target = ConnectionTarget::Host { host: "mongodb://h".into(), port: 27017 }; + + let result = repository.save(connection).await; + + assert!(matches!(result, Err(RepositoryError::Invalid(reason)) if reason.contains("connection string"))); + assert!(!dir.file().exists()); + } + + #[tokio::test] + async fn update_refuses_an_invalid_connection() { + let (_dir, _store, repository) = setup(); + let saved = repository.save(create(None)).await.unwrap(); + let mut changed = saved.clone(); + changed.name = " ".into(); + assert!(matches!(repository.update(&saved.id, &changed).await, Err(RepositoryError::Invalid(_)))); + } + + #[tokio::test] + async fn a_version_1_file_is_migrated_written_back_and_kept_as_backup() { + let (dir, store, repository) = setup(); + let v1 = r#"{ "version": 1, "connections": { + "a": { "id": "a", "name": "Local", "uri": "localhost", "port": 27017, "connector": "MongoDb", + "connectionType": "Standalone", + "authentication": { "kind": "BASIC", "username": "root", "password": null, "database": "admin" } }, + "b": { "id": "b", "name": "Atlas", "uri": "mongodb+srv://ada:pw@c.example.net", "port": 27017, + "connector": "MongoDb", "connectionType": "DnsSeedList", + "authentication": { "kind": "NONE", "username": null, "password": null, "database": null } } } }"#; + std::fs::write(dir.file(), v1).unwrap(); + store.insert("a", "kept"); + + let mut connections = repository.list().await.unwrap(); + connections.sort_by(|x, y| x.id.cmp(&y.id)); + + assert_eq!(connections[0].target, ConnectionTarget::Host { host: "localhost".into(), port: 27017 }); + assert_eq!(connections[1].target, ConnectionTarget::Uri { uri: "mongodb+srv://c.example.net".into() }); + assert_eq!(store.stored("a").as_deref(), Some("kept")); + assert_eq!(store.stored("b").as_deref(), Some("pw")); + let file = std::fs::read_to_string(dir.file()).unwrap(); + assert!(file.contains("\"version\": 2")); + assert!(!file.contains("connectionType")); + assert_eq!(std::fs::read_to_string(dir.0.join("connections.v1.json")).unwrap(), v1); + + // the second load reads version 2 and doesn't migrate again + assert_eq!(repository.list().await.unwrap().len(), 2); + } + + #[tokio::test] + async fn a_file_without_version_is_refused() { + let (dir, _store, repository) = setup(); + std::fs::write(dir.file(), r#"{ "connections": {} }"#).unwrap(); + assert!(matches!( + repository.list().await, + Err(RepositoryError::MigrationError { from: 0, .. }) + )); + } } diff --git a/src-tauri/src/connector/repositories/migrations.rs b/src-tauri/src/connector/repositories/migrations.rs new file mode 100644 index 0000000..ce09c04 --- /dev/null +++ b/src-tauri/src/connector/repositories/migrations.rs @@ -0,0 +1,160 @@ +use serde_json::Value; + +use crate::connector::commands::error::RepositoryError; +use crate::connector::models::{ + authentication::{AuthenticationKind, AuthenticationOptions}, + connection::{Connection, ConnectionTarget, ConnectorKind}, + options::ConnectionOptions, + uri::{is_connection_string, split_uri_credentials}, +}; +use crate::connector::repositories::storage_wrapper::{ConnectionStorage, STORAGE_VERSION}; + +/// A password found in a version 1 connection string; it moves to the credential store. +#[derive(Debug, PartialEq)] +pub struct MovedPassword { + pub connection_id: String, + pub password: String, +} + +/// Version 1 kept the host in `uri` next to `port`, and a `connectionType` nothing read. +/// A `uri` that is a connection string becomes a `Uri` target without its credentials. +pub fn migrate_v1(value: &Value) -> Result<(ConnectionStorage, Vec), RepositoryError> { + let invalid = || RepositoryError::MigrationError { from: 1, to: STORAGE_VERSION }; + + let connections = value + .get("connections") + .and_then(Value::as_object) + .ok_or_else(invalid)?; + + let mut storage = ConnectionStorage::new(); + let mut moved = Vec::new(); + + for (key, old) in connections { + let id = old.get("id").and_then(Value::as_str).unwrap_or(key).to_string(); + let name = old.get("name").and_then(Value::as_str).ok_or_else(invalid)?.to_string(); + let uri = old.get("uri").and_then(Value::as_str).ok_or_else(invalid)?.trim(); + let port = old + .get("port") + .and_then(Value::as_u64) + .and_then(|port| u16::try_from(port).ok()) + .unwrap_or(27017); + + let mut authentication: AuthenticationOptions = match old.get("authentication") { + Some(auth) => serde_json::from_value(auth.clone()).map_err(|_| invalid())?, + None => AuthenticationOptions::default(), + }; + authentication.password = None; + + let target = if is_connection_string(uri) { + let split = split_uri_credentials(uri).map_err(|_| invalid())?; + if split.username.is_some() || split.password.is_some() { + authentication.kind = AuthenticationKind::BASIC; + } + if authentication.username.as_deref().unwrap_or("").is_empty() { + authentication.username = split.username; + } + if let Some(password) = split.password { + moved.push(MovedPassword { connection_id: id.clone(), password }); + } + ConnectionTarget::Uri { uri: split.uri } + } else { + ConnectionTarget::Host { host: uri.to_string(), port } + }; + + storage.connections.insert( + id.clone(), + Connection { + id, + name, + connector: ConnectorKind::MongoDb, + target, + authentication, + options: ConnectionOptions::default(), + }, + ); + } + + Ok((storage, moved)) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + fn v1(connections: Value) -> Value { + json!({ "version": 1, "connections": connections }) + } + + #[test] + fn turns_host_and_port_into_a_host_target() { + let (storage, moved) = migrate_v1(&v1(json!({ + "a": { + "id": "a", "name": "Local", "uri": "localhost", "port": 27018, + "connector": "MongoDb", "connectionType": "Standalone", + "authentication": { "kind": "BASIC", "username": "root", "password": null, "database": "admin" } + } + }))) + .unwrap(); + + let connection = &storage.connections["a"]; + assert_eq!(storage.version, STORAGE_VERSION); + assert_eq!(connection.name, "Local"); + assert_eq!(connection.target, ConnectionTarget::Host { host: "localhost".into(), port: 27018 }); + assert_eq!(connection.authentication.kind, AuthenticationKind::BASIC); + assert_eq!(connection.authentication.username.as_deref(), Some("root")); + assert_eq!(connection.authentication.database.as_deref(), Some("admin")); + assert_eq!(connection.options, ConnectionOptions::default()); + assert!(moved.is_empty()); + } + + #[test] + fn turns_a_connection_string_into_a_uri_target_and_moves_its_password() { + let (storage, moved) = migrate_v1(&v1(json!({ + "b": { + "id": "b", "name": "Atlas", "uri": "mongodb+srv://ada:pw@cluster0.example.net/?retryWrites=true", + "port": 27017, "connector": "MongoDb", "connectionType": "DnsSeedList", + "authentication": { "kind": "NONE", "username": null, "password": null, "database": null } + } + }))) + .unwrap(); + + let connection = &storage.connections["b"]; + assert_eq!(connection.target, ConnectionTarget::Uri { uri: "mongodb+srv://cluster0.example.net/?retryWrites=true".into() }); + assert_eq!(connection.authentication.kind, AuthenticationKind::BASIC); + assert_eq!(connection.authentication.username.as_deref(), Some("ada")); + assert_eq!(moved, vec![MovedPassword { connection_id: "b".into(), password: "pw".into() }]); + } + + #[test] + fn defaults_a_missing_port_and_authentication_and_takes_the_key_as_id() { + let (storage, _) = migrate_v1(&v1(json!({ "k": { "name": "N", "uri": "db.local" } }))).unwrap(); + let connection = &storage.connections["k"]; + assert_eq!(connection.id, "k"); + assert_eq!(connection.target, ConnectionTarget::Host { host: "db.local".into(), port: 27017 }); + assert_eq!(connection.authentication, AuthenticationOptions::default()); + } + + #[test] + fn drops_a_password_that_was_stored_in_the_file() { + let (storage, _) = migrate_v1(&v1(json!({ + "a": { "name": "N", "uri": "h", "authentication": { "kind": "BASIC", "username": "u", "password": "leaked", "database": null } } + }))) + .unwrap(); + assert_eq!(storage.connections["a"].authentication.password, None); + } + + #[test] + fn migrates_an_empty_file() { + let (storage, moved) = migrate_v1(&v1(json!({}))).unwrap(); + assert!(storage.connections.is_empty()); + assert!(moved.is_empty()); + } + + #[test] + fn refuses_connections_without_name_or_uri() { + assert!(migrate_v1(&v1(json!({ "a": { "uri": "h" } }))).is_err()); + assert!(migrate_v1(&v1(json!({ "a": { "name": "N" } }))).is_err()); + assert!(migrate_v1(&json!({ "version": 1 })).is_err()); + } +} diff --git a/src-tauri/src/connector/repositories/mod.rs b/src-tauri/src/connector/repositories/mod.rs index fe2611c..3117c9f 100644 --- a/src-tauri/src/connector/repositories/mod.rs +++ b/src-tauri/src/connector/repositories/mod.rs @@ -1,4 +1,5 @@ pub mod connector_repository; pub mod file_repository; pub mod credentials; +pub mod migrations; pub mod storage_wrapper; \ No newline at end of file diff --git a/src-tauri/src/connector/repositories/storage_wrapper.rs b/src-tauri/src/connector/repositories/storage_wrapper.rs index 61e1731..b20891d 100644 --- a/src-tauri/src/connector/repositories/storage_wrapper.rs +++ b/src-tauri/src/connector/repositories/storage_wrapper.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use crate::connector::{ models::connection::Connection}; +use crate::connector::models::connection::Connection; -pub const STORAGE_VERSION: u32 = 1; +/// 1: `uri` held the host, plus `port` and `connectionType`. 2: `target` and `options`. +pub const STORAGE_VERSION: u32 = 2; #[derive(Serialize, Deserialize, Debug)] pub struct ConnectionStorage { @@ -19,3 +20,9 @@ impl ConnectionStorage { } } } + +impl Default for ConnectionStorage { + fn default() -> Self { + Self::new() + } +} diff --git a/src-tauri/src/drivers/client_options.rs b/src-tauri/src/drivers/client_options.rs new file mode 100644 index 0000000..130e80e --- /dev/null +++ b/src-tauri/src/drivers/client_options.rs @@ -0,0 +1,292 @@ +use std::path::PathBuf; +use std::time::Duration; + +use mongodb::options::{ClientOptions, Credential, ServerAddress, Tls, TlsOptions}; +use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; + +use crate::connector::models::{ + authentication::{AuthenticationKind, AuthenticationOptions}, + connection::{Connection, ConnectionTarget}, + options::ConnectionOptions, +}; +use crate::drivers::errors::DriverError; + +const APP_NAME: &str = "Monolens"; +const DEFAULT_AUTH_SOURCE: &str = "admin"; + +/// The driver's options for a connection, without building a URL string by hand. +/// A connection string is parsed by the driver (an srv string resolves DNS here). +pub async fn client_options(connection: &Connection) -> Result { + let mut options = match &connection.target { + ConnectionTarget::Host { host, port } => host_options(host, *port, &connection.options), + ConnectionTarget::Uri { uri } => { + let full = with_user_info(uri, &connection.authentication); + ClientOptions::parse(&full) + .await + .map_err(|e| DriverError::UriMalformed(e.to_string()))? + } + }; + + options.app_name = Some(APP_NAME.to_string()); + options.credential = credential(&connection.authentication, options.credential.take()); + + Ok(options) +} + +/// Stored connection strings carry no credentials. The driver validates some options against +/// them (an `authMechanism` needs a username), so they go back in, encoded, right before parsing. +fn with_user_info(uri: &str, auth: &AuthenticationOptions) -> String { + let Some(username) = non_empty(&auth.username) else { + return uri.to_string(); + }; + if auth.kind != AuthenticationKind::BASIC { + return uri.to_string(); + } + let Some(scheme_end) = uri.find("://").map(|i| i + 3) else { + return uri.to_string(); + }; + + let mut user_info = utf8_percent_encode(&username, NON_ALPHANUMERIC).to_string(); + if let Some(password) = &auth.password { + user_info.push(':'); + user_info.push_str(&utf8_percent_encode(password, NON_ALPHANUMERIC).to_string()); + } + + format!("{}{}@{}", &uri[..scheme_end], user_info, &uri[scheme_end..]) +} + +fn non_empty(value: &Option) -> Option { + value.as_ref().map(|v| v.trim()).filter(|v| !v.is_empty()).map(String::from) +} + +fn host_options(host: &str, port: u16, settings: &ConnectionOptions) -> ClientOptions { + let mut options = ClientOptions::builder() + .hosts(vec![ServerAddress::Tcp { + host: host.to_string(), + port: Some(port), + }]) + .build(); + + if settings.tls { + options.tls = Some(Tls::Enabled( + TlsOptions::builder() + .ca_file_path(non_empty(&settings.tls_ca_file).map(PathBuf::from)) + .allow_invalid_certificates(settings.tls_allow_invalid_certificates) + .build(), + )); + } + + options.repl_set_name = non_empty(&settings.replica_set); + options.server_selection_timeout = settings + .server_selection_timeout_secs + .map(|secs| Duration::from_secs(u64::from(secs))); + + options +} + +/// The authentication database is the form's, else the string's `authSource`, else admin. +/// A mechanism set in the connection string stays. +fn credential(auth: &AuthenticationOptions, from_uri: Option) -> Option { + match auth.kind { + AuthenticationKind::NONE => None, + AuthenticationKind::BASIC => { + let source = non_empty(&auth.database) + .or_else(|| from_uri.as_ref().and_then(|c| c.source.clone())) + .unwrap_or_else(|| DEFAULT_AUTH_SOURCE.to_string()); + + let mut credential = from_uri.unwrap_or_default(); + credential.username = auth.username.clone(); + credential.password = auth.password.clone(); + credential.source = Some(source); + Some(credential) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::connector::models::connection::ConnectorKind; + use mongodb::options::AuthMechanism; + + fn connection(target: ConnectionTarget, authentication: AuthenticationOptions, options: ConnectionOptions) -> Connection { + Connection { + id: "id".into(), + name: "test".into(), + connector: ConnectorKind::MongoDb, + target, + authentication, + options, + } + } + + fn host() -> ConnectionTarget { + ConnectionTarget::Host { host: "db.local".into(), port: 27018 } + } + + fn uri(value: &str) -> ConnectionTarget { + ConnectionTarget::Uri { uri: value.into() } + } + + fn basic(database: Option<&str>) -> AuthenticationOptions { + AuthenticationOptions { + kind: AuthenticationKind::BASIC, + username: Some("ada".into()), + password: Some("p@ss:w/rd".into()), + database: database.map(String::from), + } + } + + #[tokio::test] + async fn host_mode_uses_host_and_port_and_driver_defaults() { + let options = client_options(&connection(host(), AuthenticationOptions::default(), ConnectionOptions::default())) + .await + .unwrap(); + + assert_eq!(options.hosts, vec![ServerAddress::Tcp { host: "db.local".into(), port: Some(27018) }]); + assert_eq!(options.app_name.as_deref(), Some("Monolens")); + assert!(options.credential.is_none()); + assert!(options.tls.is_none()); + assert!(options.repl_set_name.is_none()); + assert!(options.server_selection_timeout.is_none()); + } + + #[tokio::test] + async fn host_mode_applies_tls_replica_set_and_timeout() { + let settings = ConnectionOptions { + tls: true, + tls_ca_file: Some("/etc/ssl/ca.pem".into()), + tls_allow_invalid_certificates: true, + replica_set: Some("rs0".into()), + server_selection_timeout_secs: Some(5), + }; + + let options = client_options(&connection(host(), AuthenticationOptions::default(), settings)).await.unwrap(); + + match options.tls { + Some(Tls::Enabled(tls)) => { + assert_eq!(tls.ca_file_path, Some(PathBuf::from("/etc/ssl/ca.pem"))); + assert_eq!(tls.allow_invalid_certificates, Some(true)); + } + other => panic!("expected tls, got {other:?}"), + } + assert_eq!(options.repl_set_name.as_deref(), Some("rs0")); + assert_eq!(options.server_selection_timeout, Some(Duration::from_secs(5))); + } + + #[tokio::test] + async fn host_mode_ignores_blank_option_fields() { + let settings = ConnectionOptions { + tls: true, + tls_ca_file: Some(" ".into()), + replica_set: Some("".into()), + ..ConnectionOptions::default() + }; + + let options = client_options(&connection(host(), AuthenticationOptions::default(), settings)).await.unwrap(); + + match options.tls { + Some(Tls::Enabled(tls)) => assert_eq!(tls.ca_file_path, None), + other => panic!("expected tls, got {other:?}"), + } + assert!(options.repl_set_name.is_none()); + } + + #[tokio::test] + async fn basic_authentication_sets_the_credential_unencoded() { + let options = client_options(&connection(host(), basic(Some("shop")), ConnectionOptions::default())) + .await + .unwrap(); + + let credential = options.credential.unwrap(); + assert_eq!(credential.username.as_deref(), Some("ada")); + assert_eq!(credential.password.as_deref(), Some("p@ss:w/rd")); + assert_eq!(credential.source.as_deref(), Some("shop")); + } + + #[tokio::test] + async fn the_authentication_database_defaults_to_admin() { + let options = client_options(&connection(host(), basic(Some(" ")), ConnectionOptions::default())) + .await + .unwrap(); + assert_eq!(options.credential.unwrap().source.as_deref(), Some("admin")); + } + + #[tokio::test] + async fn uri_mode_parses_hosts_and_options_from_the_string() { + let options = client_options(&connection( + uri("mongodb://h1:27017,h2:27018/?replicaSet=rs0&tls=true&serverSelectionTimeoutMS=2000"), + AuthenticationOptions::default(), + // ignored for a connection string + ConnectionOptions { replica_set: Some("other".into()), ..ConnectionOptions::default() }, + )) + .await + .unwrap(); + + assert_eq!(options.hosts.len(), 2); + assert_eq!(options.repl_set_name.as_deref(), Some("rs0")); + assert!(matches!(options.tls, Some(Tls::Enabled(_)))); + assert_eq!(options.server_selection_timeout, Some(Duration::from_millis(2000))); + assert!(options.credential.is_none()); + } + + #[tokio::test] + async fn uri_mode_keeps_auth_source_and_mechanism_of_the_string() { + let options = client_options(&connection( + uri("mongodb://h/?authSource=shop&authMechanism=SCRAM-SHA-256"), + basic(None), + ConnectionOptions::default(), + )) + .await + .unwrap(); + + let credential = options.credential.unwrap(); + assert_eq!(credential.source.as_deref(), Some("shop")); + assert_eq!(credential.mechanism, Some(AuthMechanism::ScramSha256)); + assert_eq!(credential.username.as_deref(), Some("ada")); + } + + #[tokio::test] + async fn the_form_authentication_database_wins_over_the_string() { + let options = client_options(&connection(uri("mongodb://h/?authSource=shop"), basic(Some("admin")), ConnectionOptions::default())) + .await + .unwrap(); + assert_eq!(options.credential.unwrap().source.as_deref(), Some("admin")); + } + + #[tokio::test] + async fn no_authentication_drops_a_credential_of_the_string() { + let options = client_options(&connection(uri("mongodb://h/?authSource=shop"), AuthenticationOptions::default(), ConnectionOptions::default())) + .await + .unwrap(); + assert!(options.credential.is_none()); + } + + #[tokio::test] + async fn uri_mode_round_trips_credentials_with_special_characters() { + let options = client_options(&connection(uri("mongodb://h1,h2/shop"), basic(None), ConnectionOptions::default())) + .await + .unwrap(); + + let credential = options.credential.unwrap(); + assert_eq!(credential.username.as_deref(), Some("ada")); + assert_eq!(credential.password.as_deref(), Some("p@ss:w/rd")); + assert_eq!(credential.source.as_deref(), Some("shop")); + } + + #[test] + fn user_info_is_only_added_for_basic_authentication_with_a_username() { + assert_eq!(with_user_info("mongodb+srv://c.example.net/?x=1", &basic(None)), "mongodb+srv://ada:p%40ss%3Aw%2Frd@c.example.net/?x=1"); + assert_eq!(with_user_info("mongodb://h", &AuthenticationOptions::default()), "mongodb://h"); + let no_user = AuthenticationOptions { username: Some(" ".into()), ..basic(None) }; + assert_eq!(with_user_info("mongodb://h", &no_user), "mongodb://h"); + let no_password = AuthenticationOptions { password: None, ..basic(None) }; + assert_eq!(with_user_info("mongodb://h", &no_password), "mongodb://ada@h"); + } + + #[tokio::test] + async fn a_malformed_string_is_a_uri_error() { + let result = client_options(&connection(uri("mongodb://h/?replicaSet"), AuthenticationOptions::default(), ConnectionOptions::default())).await; + assert!(matches!(result, Err(DriverError::UriMalformed(_)))); + } +} diff --git a/src-tauri/src/drivers/mod.rs b/src-tauri/src/drivers/mod.rs index e7d99f4..8b4faef 100644 --- a/src-tauri/src/drivers/mod.rs +++ b/src-tauri/src/drivers/mod.rs @@ -1,3 +1,4 @@ +pub mod client_options; pub mod driver; pub mod errors; pub mod factory; diff --git a/src-tauri/src/drivers/mongo_official_driver.rs b/src-tauri/src/drivers/mongo_official_driver.rs index fe26103..4f69cd1 100644 --- a/src-tauri/src/drivers/mongo_official_driver.rs +++ b/src-tauri/src/drivers/mongo_official_driver.rs @@ -1,5 +1,6 @@ use crate::{ - connector::models::{authentication::AuthenticationKind, connection::Connection}, database::models::find_document::FindDocumentsResult, drivers::{ + connector::models::connection::Connection, database::models::find_document::FindDocumentsResult, drivers::{ + client_options::client_options, driver::{DatabaseDriver, ProgressCallback, TestStage}, errors::DriverError, } @@ -20,65 +21,24 @@ impl MongoDbOfficialDriver { connection, } } - - fn build_connection_string(&self) -> Result { - let conn = &self.connection; - let mut uri = match url::Url::parse(format!("mongodb://{}", &conn.uri).as_str()) { - Ok(res) => res, - Err(err) => { - log::warn!("Uri malformed: {}", err); - return Err(DriverError::UriMalformed(err.to_string())); - } - }; - - uri.set_port(Some(conn.port)).map_err(|_| { - DriverError::UriMalformed(format!("Could not set port to {}", conn.port)) - })?; - - let mut query: Vec = Vec::new(); - - match &conn.authentication.kind { - AuthenticationKind::BASIC => { - uri.set_username(conn.authentication.username.as_deref().unwrap_or("root")) - .map_err(|_| { - DriverError::UriMalformed(String::from("Could not set username")) - })?; - uri.set_password(conn.authentication.password.as_deref()) - .map_err(|_| { - DriverError::UriMalformed(String::from("Could not set password")) - })?; - } - AuthenticationKind::NONE => {} - }; - - let auth_db = conn.authentication.database.as_deref().unwrap_or("admin"); - - if !auth_db.is_empty() { - query.push(format!("authSource={}", auth_db)); - } - - uri.set_query(Some(query.join("&").as_str())); - - if cfg!(debug_assertions) { - let mut log_uri = uri.clone(); - if log_uri.password().is_some() { - let _ = log_uri.set_password(Some("***")); - } - log::debug!("Built connection query: {}", log_uri.as_str()); - } - - Ok(uri.to_string()) - } } #[async_trait] impl DatabaseDriver for MongoDbOfficialDriver { async fn connect(&mut self) -> Result<(), DriverError> { if self.client.is_none() { - let connection_string = self.build_connection_string()?; + let options = client_options(&self.connection).await?; + // never the credential: hosts and settings only + log::debug!( + "Client for {}: hosts {:?}, tls {}, replica set {:?}, authentication {}", + self.connection.name, + options.hosts, + options.tls.is_some(), + options.repl_set_name, + options.credential.is_some(), + ); self.client = Some( - Client::with_uri_str(&connection_string) - .await + Client::with_options(options) .map_err(|e| DriverError::ConnectionFailed(e.to_string()))?, ); } @@ -237,3 +197,83 @@ impl DatabaseDriver for MongoDbOfficialDriver { Ok(FindDocumentsResult { documents, total_count }) } } + +/// Against a real MongoDB, skipped by default. Run with a server and its root account: +/// MONGODB_TEST_HOST=127.0.0.1 MONGODB_TEST_PORT=27017 MONGODB_TEST_USER=root MONGODB_TEST_PASSWORD=… cargo test -- --ignored +#[cfg(test)] +mod integration { + use super::*; + use crate::connector::models::{ + authentication::{AuthenticationKind, AuthenticationOptions}, + connection::{ConnectionTarget, ConnectorKind}, + options::ConnectionOptions, + }; + + fn env(name: &str) -> String { + std::env::var(name).unwrap_or_else(|_| panic!("{name} is not set")) + } + + fn root(password: Option) -> AuthenticationOptions { + AuthenticationOptions { + kind: AuthenticationKind::BASIC, + username: Some(env("MONGODB_TEST_USER")), + password: Some(password.unwrap_or_else(|| env("MONGODB_TEST_PASSWORD"))), + database: Some("admin".into()), + } + } + + fn host() -> ConnectionTarget { + ConnectionTarget::Host { + host: env("MONGODB_TEST_HOST"), + port: env("MONGODB_TEST_PORT").parse().unwrap(), + } + } + + fn connection(target: ConnectionTarget, authentication: AuthenticationOptions) -> Connection { + Connection { + id: "integration".into(), + name: "integration".into(), + connector: ConnectorKind::MongoDb, + target, + authentication, + options: ConnectionOptions { + server_selection_timeout_secs: Some(5), + ..ConnectionOptions::default() + }, + } + } + + async fn connected(connection: Connection) -> MongoDbOfficialDriver { + let mut driver = MongoDbOfficialDriver::new(connection); + driver.connect().await.unwrap(); + driver + } + + #[tokio::test] + #[ignore] + async fn connects_by_host_and_lists_databases() { + let driver = connected(connection(host(), root(None))).await; + let databases = driver.list_databases().await.unwrap(); + assert!(databases.contains(&"admin".to_string()), "{databases:?}"); + } + + #[tokio::test] + #[ignore] + async fn connects_by_connection_string_with_separate_credentials() { + let uri = format!( + "mongodb://{}:{}/?serverSelectionTimeoutMS=5000", + env("MONGODB_TEST_HOST"), + env("MONGODB_TEST_PORT") + ); + let driver = connected(connection(ConnectionTarget::Uri { uri }, root(None))).await; + assert!(driver.list_databases().await.unwrap().contains(&"admin".to_string())); + } + + #[tokio::test] + #[ignore] + async fn a_wrong_password_is_an_authentication_error() { + let driver = connected(connection(host(), root(Some("wrong".into())))).await; + let err = driver.list_databases().await.unwrap_err(); + assert!(err.user_message().starts_with("Authentication failed"), "{err:?}"); + } +} diff --git a/src/components/connection/ConnectionDialog.vue b/src/components/connection/ConnectionDialog.vue index 4a1a446..028bd04 100644 --- a/src/components/connection/ConnectionDialog.vue +++ b/src/components/connection/ConnectionDialog.vue @@ -20,8 +20,8 @@ import { Eye, EyeOff } from '@lucide/vue'; import { useConnectionStore } from '@/stores/connectionStore'; import { AuthenticationKind, - ConnectionType, ConnectorKind, + defaultConnectionOptions, type Connection } from '@/domains/connections'; import { useLogger } from '@/composables/useLogger'; @@ -58,7 +58,7 @@ const dialogDescription = computed(() => const formSchema = z.object({ name: z.string().min(1, 'Name is required'), - uri: z.string().min(1, 'Host is required'), + host: z.string().trim().min(1, 'Host is required'), port: z.number().int().min(1).max(65535), useAuth: z.boolean(), username: z.string(), @@ -71,7 +71,7 @@ type SubmitAction = { action: 'test' | 'save' }; const defaultValues: FormValues = { name: '', - uri: 'localhost', + host: 'localhost', port: 27017, useAuth: false, username: '', @@ -107,10 +107,12 @@ watch(() => props.connection, async (conn) => { if (useAuth && props.mode === 'edit') { password = (await store.getConnectionPassword(conn.id)) ?? ''; } + // connection strings get their own fields with the next step; until then the host field shows them + const target = conn.target; form.reset({ name: conn.name, - uri: conn.uri, - port: conn.port, + host: target.kind === 'Host' ? target.host : target.uri, + port: target.kind === 'Host' ? target.port : 27017, useAuth, username: conn.authentication.username || '', password, @@ -132,10 +134,9 @@ const showPassword = ref(false); function buildConnectionFromForm(values: FormValues): Omit { return { name: values.name, - uri: values.uri, - port: values.port, connector: ConnectorKind.MongoDb, - connectionType: ConnectionType.Standalone, + target: { kind: 'Host', host: values.host.trim(), port: values.port }, + options: props.connection?.options ?? defaultConnectionOptions(), authentication: { kind: values.useAuth ? AuthenticationKind.BASIC : AuthenticationKind.NONE, username: values.useAuth && values.username ? values.username : null, @@ -175,9 +176,9 @@ const useAuth = computed(() => values.value.useAuth); const everythingFilled = computed(() => { const v = values.value; if (v.useAuth) { - return Boolean(v.name && v.uri && v.port && v.username && v.password && v.authDatabase); + return Boolean(v.name && v.host && v.port && v.username && v.password && v.authDatabase); } - return Boolean(v.name && v.uri && v.port); + return Boolean(v.name && v.host && v.port); }); @@ -210,7 +211,7 @@ const everythingFilled = computed(() => {
- +